Rolling Back Changesets

From n² wiki

Jump to: navigation, search

Nearby: Changesets

If changesets are posted to a /changesets URI, they will be saved in the store, which means that it is possible to undo the changes.

Here is how I am trying to rollback changes. I am not 100% sure it's water-tight, so suggestions and flaw-finding welcome.

First, I do a SPARQL CONSTRUCT that creates a new changeset, which adds all the statements that have been deleted in all the changesets between now and a given changeset in the past, and removes all the statements that were added in those changesets.

Then, I parse that CONSTRUCTed ChangeSet, and iterate through all the 'addition' statements, checking if they are equivalent to any of the 'removal' statements, and if so, removing that 'addition' triple and the 'removal' triple from the changeset resource. Then I reserialise the changeset as RDF/XML and post it off.

The CONSTRUCT query looks like this:

	PREFIX cs:<http://purl.org/vocab/changeset/schema#>
	PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>

	CONSTRUCT
	{
		<http://talis.com/rollback/bnode#bnode> a cs:ChangeSet ;
		cs:createdDate "{$current_date}" ;
		cs:addition ?deleted ;
		cs:removal ?added ;
		cs:creatorName "Rollback" ;
		cs:changeReason "Rollback" ;
		cs:subjectOfChange <{$subject_of_change}> .

		?deleted rdf:subject <{$subject_of_change}> .
		?deleted rdf:predicate ?del_p .
		?deleted rdf:object ?del_o .
		?deleted rdf:type rdf:Statement .

		?added rdf:subject <{$subject_of_change}> .
		?added rdf:predicate ?add_p .
		?added rdf:object ?add_o .
		?added  rdf:type rdf:Statement .

	}
	WHERE 
	{
		<{$backto_uri}> a cs:ChangeSet ;
				cs:createdDate "{$backto_date}" ;
		 		cs:subjectOfChange <{$subject_of_change>}> .

		?following cs:subjectOfChange <{$subject_of_change}> ;
				   cs:createdDate ?f_date .


		OPTIONAL
		{
			?following cs:removal ?deleted . 
				?deleted rdf:subject <{$subject_of_change}> .
				?deleted rdf:predicate ?del_p .
				?deleted rdf:object ?del_o .
				?deleted rdf:type rdf:Statement .		
		} 

		OPTIONAL
		{
			?following cs:addition ?added . 
			?added rdf:subject <{$subject_of_change}> .
			?added rdf:predicate ?add_p .
			?added rdf:object ?add_o .
			?added  rdf:type rdf:Statement .
		} 

		FILTER(?f_date >= "{$backto_date}") .
	}

NB: the {$backto_uri} variables are templated into the SPARQL query - they would be real values in the actual query sent.

The <http://talis.com/rollback/bnode#bnode> URI is necessary in the query so that only one changeset is returned, but we replace this URI with a blank node before sending the changeset to the platform (and the platform will give the changeset a new unique URI).

I then have to massage the rollback to remove removal/addition statements that cancel each other out. Any statements that refer to etags also need to be removed because the etag is a property auto-generated by the platform, so if you try to undo that you will get an error because the etag is no longer the same as it was when it was submitted (you cannot set the etag yourself).

I don't think it's possible to do all of this in the sparql query because a FILTER on the statements would also FILTER out the changeset the statement belonged to (I think). It'd be great if anyone proves me wrong though. User:Keithalexander

Personal tools