``` javascript
const logA = [
{
logId: 1,
author: "ABC",
seqNo: 1,
entryHash: "123A",
referenceHash: null,
message: {
action: "create",
fields: { text: "Pandas like to eat bamboo." },
},
},
{
logId: 1,
author: "ABC",
seqNo: 2,
entryHash: "123B",
referenceHash: "123A",
message: {
id: "123A",
action: "update",
fields: { text: "Pandas LOVE to eat bamboo." },
},
},
{
logId: 1,
author: "ABC",
seqNo: 3,
entryHash: "123C",
referenceHash: "123B",
message: {
id: "123A",
action: "update",
fields: { text: "Pandas LOVE to eat bamboo!" },
},
},
{
logId: 1,
author: "ABC",
seqNo: 4,
entryHash: "123D",
referenceHash: "234A",
message: {
id: "123A",
action: "update",
fields: { text: "Pandas LOVE to eat bamboo! But they HATE anchovies..." },
},
},
];
const logB = [
{
logId: 1,
author: "DEF",
seqNo: 1,
entryHash: "234A",
referenceHash: "123C",
message: {
id: "123A",
action: "update",
fields: { text: "Pandas LOVE to eat bamboo! But they hate anchovies..." },
},
},
{
logId: 1,
author: "DEF",
seqNo: 2,
entryHash: "234B",
referenceHash: "345A",
message: {
id: "123A",
action: "update",
fields: {
text: "Pandas **LOVE** to eat bamboo! But they **HATE** anchovies and black coffee...",
},
},
},
{
logId: 1,
author: "DEF",
seqNo: 3,
entryHash: "234C",
referenceHash: null,
message: {
action: "create",
fields: { text: "Pandas have big eyes." },
},
},
];
const logC = [
{
logId: 1,
author: "GHI",
seqNo: 1,
entryHash: "345A",
referenceHash: "123D",
message: {
id: "123A",
action: "update",
fields: {
text: "Pandas LOVE to eat bamboo! But they HATE anchovies and black coffee...",
},
},
},
{
logId: 1,
author: "GHI",
seqNo: 2,
entryHash: "345B",
referenceHash: "234C",
message: {
id: "234C",
action: "update",
fields: {
text: "Pandas have markings on their face which makes their eyes look big.",
},
},
},
];
// Iterator which yields all root "create" entries
function* iterateRootEntries(allEntries) {
for (entry of allEntries) {
if (entry.message.action === "create") {
yield entry;
}
}
}
// Iterator which plots update path for a root "create" entry
function* iterateUpdatePath(currentEntry, allEntries) {
while (true) {
let nextEntry = allEntries.find(
(entry) => entry.referenceHash === currentEntry.entryHash
);
if (!nextEntry) break;
currentEntry = nextEntry;
yield formatLogItem(nextEntry);
}
}
const createDataTree = (allEntries) => {
const dataTree = [];
const rootEntries = iterateRootEntries(allEntries);
let createMessage = rootEntries.next();
while (!createMessage.done) {
dataTree.push([
formatLogItem(createMessage.value),
...iterateUpdatePath(createMessage.value, allEntries),
]);
createMessage = rootEntries.next();
}
return dataTree;
};
const createMaterializedView = (dataTree) => {
let materializedView = {};
for (path of dataTree) {
materializedView[path[path.length - 1].id] = path[path.length - 1].value;
}
return materializedView;
};
const formatLogItem = (entry) => {
return {
id: entry.message.id ? entry.message.id : entry.entryHash,
author: entry.author,
value: entry.message.fields.text,
};
};
const allEntries = [...logA, ...logB, ...logC];
const dataTree = createDataTree(allEntries);
console.log(dataTree); // => change log for each create message
let materializedView = createMaterializedView(dataTree);
console.log(materializedView); // => final updated message state
/*
{
'123A': 'Pandas **LOVE** to eat bamboo! But they **HATE** anchovies and black coffee...',
'234C': 'Pandas have markings on their face which makes their eyes look big.'
}
*/
```