Skip to content

Instantly share code, notes, and snippets.

@frankshaka
Created May 13, 2019 10:46
Show Gist options
  • Save frankshaka/caa3ec35a4a9a80fc9063297e069b0a6 to your computer and use it in GitHub Desktop.
Save frankshaka/caa3ec35a4a9a80fc9063297e069b0a6 to your computer and use it in GitHub Desktop.
Automerge for moving topics
const Automerge = require('automerge')
function printTopicTree(topic, indent = 2) {
let text = '* ' + topic.id
for (let i = 0; i < indent; i++) {
text = ' ' + text
}
console.log(text)
for (let subtopic of topic.topics) {
printTopicTree(subtopic, indent + 2)
}
}
let baseDoc1 = Automerge.init()
baseDoc1 = Automerge.change(baseDoc1, 'Set initial data', doc => {
doc.rootTopic = {
id: 'T1',
topics: [
{
id: 'T2',
topics: [
{ id: 'T100', topics: [] }
]
},
{
id: 'T3',
topics: []
},
{
id: 'T4',
topics: []
}
]
}
})
let baseDoc2 = Automerge.init()
baseDoc2 = Automerge.merge(baseDoc2, baseDoc1)
console.log('Base Doc:')
console.log('-------------------------')
printTopicTree(baseDoc1.rootTopic)
console.log('')
let doc1 = Automerge.change(baseDoc1, 'Move T100 to T3', doc => {
let t2 = doc.rootTopic.topics[0]
let t3 = doc.rootTopic.topics[1]
let t100 = t2.topics[0]
delete t2.topics[0]
t3.topics.push(t100)
})
console.log('Doc (Device 1):')
console.log('-------------------------')
printTopicTree(doc1.rootTopic)
console.log('')
let doc2 = Automerge.change(baseDoc2, 'Move T100 to T4', doc => {
let t2 = doc.rootTopic.topics[0]
let t4 = doc.rootTopic.topics[2]
let t100 = t2.topics[0]
delete t2.topics[0]
t4.topics.push(t100)
})
console.log('Doc (Device 2):')
console.log('-------------------------')
printTopicTree(doc2.rootTopic)
console.log('')
let finalDoc = Automerge.merge(doc1, doc2)
console.log('Merged Doc:')
console.log('-------------------------')
printTopicTree(findlDoc.rootTopic)
@MichaelDuo
Copy link

I think to avoid this type of error, the value assigned to a key should be a newly created object, Automerge internally has id for each object, and assigning same one to different parent indeed will confuse the algorithm.
Quick fix for this code:
change line 57 to t3.topics.push(JSON.parse(JSON.stringify(t100)))
change line 65 to t4.topics.push(JSON.parse(JSON.stringify(t100)))
It will create two copies of t100 under t3 and t4.

@MichaelDuo
Copy link

Since duplicated id is not acceptable, here's another solution.
We have another doc, say, docServer, doc1 commit it's changes to docServer, then doc2 commit it's change to docServer.
Like this:

let finalDoc = Automerge.merge(docServer, doc1)
finalDoc = Automerge.merge(docServer, doc2)

the delete action in doc2 will be performed correctly and remain only one topic.

@frankshaka
Copy link
Author

@MichaelDuo Doesn’t the third doc break the sync? In a production scenario, doc1 is kept on device 1, and doc2 on device 2. Where do we keep docServer? And how does it sync to each device?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment