@@ -322,7 +322,81 @@ def read_target
322322 end
323323
324324 public
325-
325+
326+ ##
327+ # A transaction with full serializability.
328+ #
329+ # @todo refactor me!
330+ # @see RDF::Transaction
331+ class SerializedTransaction < Transaction
332+ ##
333+ # @see Transaction#initialize
334+ def initialize ( *args , **options , &block )
335+ super ( *args , **options , &block )
336+ @base_snapshot = @snapshot
337+ end
338+
339+ ##
340+ # Inserts the statement to the transaction's working snapshot.
341+ #
342+ # @see Transaction#insert_statement
343+ def insert_statement ( statement )
344+ @snapshot = @snapshot . class
345+ . new ( data : @snapshot . send ( :insert_to ,
346+ @snapshot . send ( :data ) ,
347+ process_statement ( statement ) ) )
348+ end
349+
350+ ##
351+ # Deletes the statement from the transaction's working snapshot.
352+ #
353+ # @see Transaction#insert_statement
354+ def delete_statement ( statement )
355+ @snapshot = @snapshot . class
356+ . new ( data : @snapshot . send ( :delete_from ,
357+ @snapshot . send ( :data ) ,
358+ process_statement ( statement ) ) )
359+ end
360+
361+ ##
362+ # @see RDF::Dataset#isolation_level
363+ def isolation_level
364+ :serializable
365+ end
366+
367+ ##
368+ # @note this is a simple object equality check.
369+ #
370+ # @see RDF::Transaction#mutated?
371+ def mutated?
372+ !@snapshot . send ( :data ) . equal? ( repository . send ( :data ) )
373+ end
374+
375+ ##
376+ # Replaces repository data with the transaction's snapshot in a safely
377+ # serializable fashion.
378+ #
379+ # @note this transaction uses a pessimistic merge strategy which
380+ # fails the transaction if any data has changed in the repository
381+ # since transaction start time. However, the specific guarantee is
382+ # softer: multiple concurrent conflicting transactions will not
383+ # succeed. We may choose to implement a less pessimistic merge
384+ # strategy as a non-breaking change.
385+ #
386+ # @raise [TransactionError] when the transaction can't be merged.
387+ # @see Transaction#execute
388+ def execute
389+ raise TransactionError , 'Cannot execute a rolled back transaction. ' \
390+ 'Open a new one instead.' if instance_variable_defined? ( :@rolledback ) && @rolledback
391+
392+ raise TransactionError , 'Error merging transaction. Repository' \
393+ 'has changed during transaction time.' unless
394+ repository . send ( :data ) . equal? @base_snapshot . send ( :data )
395+
396+ repository . send ( :data= , @snapshot . send ( :data ) )
397+ end
398+ end # SerializedTransaction
399+
326400 ##
327401 # An error class for transaction failures.
328402 #
0 commit comments