Een oplossing waar ik nu aan werk, die tot nu toe goed werkt, implementeert het ontwerp dat ik in de vraag heb voorgesteld
Ik zal de details van mijn implementatie hier delen
Voor het maken van delta's en het gebruik van de om de volledige tekst te reconstrueren, gebruik ik de fantastische google-diff-match-patch-bibliotheek . U kunt de implementatie-agnostische API-documentatie lezen om de onderstaande codevoorbeelden beter te begrijpen, hoewel het hoe dan ook goed leesbaar is.
google-diff-match-patch heeft Java- en JS-implementaties, dus ik kan het gebruiken om de delta's met Java op de server te berekenen. Ik heb ervoor gekozen om elke delta naar een string te converteren, zodat deze gemakkelijk kan worden opgeslagen in de database en gemakkelijk kan worden gebruikt door de JS-bibliotheek op de client. Hieronder meer hierover.
public String getBackwardsDelta(String editedBlogPost, String existingBlogPost) {
diff_match_patch dmp = new diff_match_patch();
LinkedList<diff_match_patch.Patch> patches =
dmp.patch_make(editedBlogPost, existingBlogPost);
return dmp.patch_toText(patches);
}
NB het kostte me een tijdje om erachter te komen hoe ik de officiële build van google-diff-match-patch kon verwijderen maven gebruiken. Het staat niet in de maven centrale repo, maar op hun eigen repo op googlecode.com. Om op te merken, sommige mensen hebben het geforked en hun gevorkte versies in maven central geplaatst, maar als je echt de officiële versie wilt, kun je deze krijgen door de repo en afhankelijkheid toe te voegen aan je pom.xml
als volgt
<repository>
<id>google-diff-patch-match</id>
<name>google-diff-patch-match</name>
<url>https://google-diff-match-patch.googlecode.com/svn/trunk/maven/</url>
</repository>
<dependency>
<groupId>diff_match_patch</groupId>
<artifactId>diff_match_patch</artifactId>
<version>current</version>
</dependency>
Voor de front-end geef ik de laatste blogpost full-text door, samen met een reeks delta's die teruggaan in de tijd die elke bewerking vertegenwoordigen, en reconstrueer vervolgens de volledige tekst van elke versie in de browser in JS.
Om de bibliotheek te krijgen, gebruik ik npm + browserify. De bibliotheek is beschikbaar op npm als diff-match-patch . Versie 1.0.0 is de enige versie.
getTextFromDelta: function(originalText, delta) {
var DMP = require('diff-match-patch'); // get the constructor function
var dmp = new DMP();
var patches = dmp.patch_fromText(delta);
return dmp.patch_apply(patches, originalText)[0];
}
En dat is alles, het werkt fantastisch.
Wat betreft het opslaan van de bewerkingen van de blogposts, gebruik ik gewoon een tabel BLOG_POST_EDITS
waar ik de blogpost-ID opsla, een tijdstempel van wanneer de bewerking is gemaakt (die ik later gebruik om de bewerkingen correct te ordenen om de ketting te maken bij het reconstrueren van de volledige tekstversies op de client), en de achterwaartse delta tussen de huidige live blogbericht in de BLOG_POST
tabel en de inkomende bewerkte versie van de blogpost.
Ik heb ervoor gekozen om een 'keten' van delta's op te slaan omdat dit goed past bij mijn gebruikssituatie en eenvoudiger is aan het einde van de servercode. Het betekent wel dat om versie M van N te reconstrueren, ik de klant een reeks N-(M-1) delta's moet terugsturen van de live blogpost full-text naar versie M. Maar in mijn gebruiksgeval heb ik toevallig wil toch elke keer de hele keten verzenden, dus dit is prima.
Voor een iets betere over-the-wire efficiëntie voor het aanvragen van specifieke versies, zouden alle delta's herberekend kunnen worden van de nieuwe bewerkte blogpost-versie terug naar elke (herstelde) versie elke keer dat er een bewerking wordt gemaakt, maar dit zou meer werk en complexiteit betekenen op de server.