Uma solução em que estou trabalhando agora, que está funcionando bem até agora, implementa o design que propus na pergunta
Vou compartilhar os detalhes da minha implementação aqui
Para criar deltas e usar o para reconstruir o texto completo, estou usando o fantástico biblioteca google-diff-match-patch . Você pode ler a documentação da API independente de implementação para entender melhor os exemplos de código abaixo, embora seja bastante legível de qualquer maneira.
google-diff-match-patch tem implementações Java e JS para que eu possa usá-lo para calcular os deltas com Java no servidor. Optei por converter cada delta em uma String tanto para que possa ser facilmente armazenado no banco de dados, quanto facilmente consumido pela biblioteca JS no cliente. Mais sobre isso abaixo.
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);
}
N.B. algo que demorei um pouco para descobrir foi como baixar a versão oficial do google-diff-match-patch usando maven. Não está no repositório central do maven, mas em seu próprio repositório no googlecode.com. Apenas para observar, algumas pessoas fizeram um fork e colocaram suas versões bifurcadas no maven central, mas se você realmente deseja a versão oficial, pode obter adicionando o repositório e a dependência em seu
pom.xml
do seguinte modo <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>
Para o front-end, passo o texto completo da última postagem do blog, juntamente com uma cadeia de deltas voltando no tempo representando cada edição e, em seguida, reconstruo o texto completo de cada versão no navegador em JS.
Para obter a biblioteca, estou usando npm + browserify. A biblioteca está disponível no npm como diff-match-patch . A versão 1.0.0 é a única versão.
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];
}
E é isso, funciona fantasticamente.
Em termos de armazenamento das edições dos posts do blog, apenas uso uma tabela
BLOG_POST_EDITS
onde armazeno o ID do post do blog, um carimbo de data e hora de quando a edição foi feita (que depois uso para ordenar as edições corretamente para fazer a cadeia ao reconstruir as versões de texto completo no cliente) e o delta inverso entre a live atual postagem do blog no BLOG_POST
tabela e a versão editada recebida da postagem do blog. Eu escolhi armazenar uma 'cadeia' de deltas porque se adequa bem ao meu caso de uso e é mais simples no final do código do servidor. Isso significa que, para reconstruir a versão M de N, tenho que enviar ao cliente uma cadeia de N-(M-1) deltas de volta do texto completo da postagem do blog ao vivo para a versão M. Mas, no meu caso de uso, por acaso deseja enviar toda a cadeia de cada vez, de qualquer maneira, então tudo bem.
Para uma eficiência um pouco melhor over-the-wire para solicitar versões específicas, todos os deltas podem ser recalculados da nova versão editada da postagem do blog para cada versão (restaurada) cada vez que uma edição é feita, mas isso significaria mais trabalho e complexidade no servidor.