@@ -177,11 +177,48 @@ impl Dataset {
177177 }
178178 Ok ( Transaction :: new ( self ) )
179179 }
180+
181+ /// Optionally start a transaction before running `func` for performance
182+ ///
183+ /// This uses transaction if the dataset supports it, otherwise it
184+ /// runs the `func` function as it is on the dataset. If the
185+ /// closure results in error, and it is a transaction, it is
186+ /// rolled back. If there is error in rollback it is ignored.
187+ pub fn maybe_batch ( & mut self , func : impl Fn ( & Dataset ) -> Result < ( ) > ) -> Result < ( ) > {
188+ let force = 0 ; // since this is for speed
189+ let rv = unsafe { gdal_sys:: GDALDatasetStartTransaction ( self . c_dataset ( ) , force) } ;
190+ if rv == OGRErr :: OGRERR_UNSUPPORTED_OPERATION {
191+ func ( self )
192+ } else if rv == OGRErr :: OGRERR_NONE {
193+ let res = func ( self ) ;
194+ if res. is_ok ( ) {
195+ let rv = unsafe { gdal_sys:: GDALDatasetCommitTransaction ( self . c_dataset ( ) ) } ;
196+ if rv != OGRErr :: OGRERR_NONE {
197+ Err ( GdalError :: OgrError {
198+ err : rv,
199+ method_name : "GDALDatasetCommitTransaction" ,
200+ } )
201+ } else {
202+ res
203+ }
204+ } else {
205+ let _ = unsafe { gdal_sys:: GDALDatasetRollbackTransaction ( self . c_dataset ( ) ) } ;
206+ // ignoring rollback error
207+ res
208+ }
209+ } else {
210+ // transaction supported but failed
211+ Err ( GdalError :: OgrError {
212+ err : rv,
213+ method_name : "GDALDatasetStartTransaction" ,
214+ } )
215+ }
216+ }
180217}
181218
182219#[ cfg( test) ]
183220mod tests {
184- use crate :: test_utils:: { fixture, open_gpkg_for_update} ;
221+ use crate :: test_utils:: { fixture, open_dataset_for_update , open_gpkg_for_update} ;
185222 use crate :: vector:: { Geometry , LayerAccess } ;
186223 use crate :: Dataset ;
187224
@@ -241,4 +278,30 @@ mod tests {
241278 let mut ds = Dataset :: open ( fixture ( "roads.geojson" ) ) . unwrap ( ) ;
242279 assert ! ( ds. start_transaction( ) . is_err( ) ) ;
243280 }
281+
282+ #[ test]
283+ fn test_maybe_batch ( ) {
284+ let ( _temp_path, mut ds) = open_gpkg_for_update ( & fixture ( "poly.gpkg" ) ) ;
285+ let orig_feature_count = ds. layer ( 0 ) . unwrap ( ) . feature_count ( ) ;
286+
287+ let res = ds. maybe_batch ( |d| {
288+ let mut layer = d. layer ( 0 ) . unwrap ( ) ;
289+ layer. create_feature ( polygon ( ) )
290+ } ) ;
291+ assert ! ( res. is_ok( ) ) ;
292+ assert_eq ! ( ds. layer( 0 ) . unwrap( ) . feature_count( ) , orig_feature_count + 1 ) ;
293+ }
294+
295+ #[ test]
296+ fn test_maybe_transaction_unsupported ( ) {
297+ let ( _temp_path, mut ds) = open_dataset_for_update ( & fixture ( "roads.geojson" ) ) ;
298+ let orig_feature_count = ds. layer ( 0 ) . unwrap ( ) . feature_count ( ) ;
299+
300+ let res = ds. maybe_batch ( |d| {
301+ let mut layer = d. layer ( 0 ) . unwrap ( ) ;
302+ layer. create_feature ( polygon ( ) )
303+ } ) ;
304+ assert ! ( res. is_ok( ) ) ;
305+ assert_eq ! ( ds. layer( 0 ) . unwrap( ) . feature_count( ) , orig_feature_count + 1 ) ;
306+ }
244307}
0 commit comments