@@ -177,11 +177,54 @@ 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.
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 rv = unsafe { gdal_sys:: GDALDatasetRollbackTransaction ( self . c_dataset ( ) ) } ;
206+ if rv != OGRErr :: OGRERR_NONE {
207+ Err ( GdalError :: OgrError {
208+ err : rv,
209+ method_name : "GDALDatasetRollbackTransaction" ,
210+ } )
211+ } else {
212+ res
213+ }
214+ }
215+ } else {
216+ // transaction supported but failed
217+ Err ( GdalError :: OgrError {
218+ err : rv,
219+ method_name : "GDALDatasetStartTransaction" ,
220+ } )
221+ }
222+ }
180223}
181224
182225#[ cfg( test) ]
183226mod tests {
184- use crate :: test_utils:: { fixture, open_gpkg_for_update} ;
227+ use crate :: test_utils:: { fixture, open_dataset_for_update , open_gpkg_for_update} ;
185228 use crate :: vector:: { Geometry , LayerAccess } ;
186229 use crate :: Dataset ;
187230
@@ -241,4 +284,30 @@ mod tests {
241284 let mut ds = Dataset :: open ( fixture ( "roads.geojson" ) ) . unwrap ( ) ;
242285 assert ! ( ds. start_transaction( ) . is_err( ) ) ;
243286 }
287+
288+ #[ test]
289+ fn test_maybe_batch ( ) {
290+ let ( _temp_path, mut ds) = open_gpkg_for_update ( & fixture ( "poly.gpkg" ) ) ;
291+ let orig_feature_count = ds. layer ( 0 ) . unwrap ( ) . feature_count ( ) ;
292+
293+ let res = ds. maybe_batch ( |d| {
294+ let mut layer = d. layer ( 0 ) . unwrap ( ) ;
295+ layer. create_feature ( polygon ( ) )
296+ } ) ;
297+ assert ! ( res. is_ok( ) ) ;
298+ assert_eq ! ( ds. layer( 0 ) . unwrap( ) . feature_count( ) , orig_feature_count + 1 ) ;
299+ }
300+
301+ #[ test]
302+ fn test_maybe_transaction_unsupported ( ) {
303+ let ( _temp_path, mut ds) = open_dataset_for_update ( & fixture ( "roads.geojson" ) ) ;
304+ let orig_feature_count = ds. layer ( 0 ) . unwrap ( ) . feature_count ( ) ;
305+
306+ let res = ds. maybe_batch ( |d| {
307+ let mut layer = d. layer ( 0 ) . unwrap ( ) ;
308+ layer. create_feature ( polygon ( ) )
309+ } ) ;
310+ assert ! ( res. is_ok( ) ) ;
311+ assert_eq ! ( ds. layer( 0 ) . unwrap( ) . feature_count( ) , orig_feature_count + 1 ) ;
312+ }
244313}
0 commit comments