all files / collab/ SnapshotEngine.js

80.56% Statements 29/36
65% Branches 13/20
100% Functions 5/5
85.29% Lines 29/34
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85                                                                                                               
import computeSnapshot from './computeSnapshot'
 
const EMPTY_DOC = { nodes: {} }
 
/*
  API for creating and retrieving document snapshots
*/
class SnapshotEngine {
  constructor(config) {
    this.changeStore = config.changeStore
    this.snapshotStore = config.snapshotStore
  }
 
  /*
    Compute snapshot for given documentId and version
 
    Example: Let's assume we want to request a snapshot for a new version 20.
    Now getClosestSnapshot will give us version 15. This requires us to fetch
    the changes since version 16 and apply those, plus the very new change.
  */
  getSnapshot(documentId, version, cb) {
    let jsonDoc = EMPTY_DOC
    this._getClosestSnapshot(documentId, version, (err, snapshot, closestVersion) => {
      Iif (err) {
        return cb(err)
      }
      if (snapshot && version === closestVersion) {
        // we alread have a snapshot for this version
        return cb(null, snapshot, version)
      }
      let knownVersion
      Iif (snapshot) {
        knownVersion = closestVersion
      } else {
        knownVersion = 0 // we need to fetch all changes
      }
      Iif (snapshot) {
        jsonDoc = snapshot
      }
      // Now we get the remaining changes after the known version
      this.changeStore.getChanges(documentId, knownVersion, version, (err, changes) => {
        Iif (err) return cb(err)
        if (changes.length < (version - knownVersion)) {
          return cb('Changes missing for reconstructing version '+ version)
        }
        jsonDoc = computeSnapshot(jsonDoc, changes)
        cb(null, jsonDoc, version)
      })
    })
  }
 
  /*
    Creates a snapshot
  */
  createSnapshot(documentId, version, cb) {
    this.getSnapshot(documentId, version, (err, snapshot) => {
      Iif (err) return cb(err)
      this.snapshotStore.saveSnapshot(documentId, version, snapshot, cb)
    })
  }
 
  _getClosestSnapshot(documentId, version, cb) {
    let closestVersion
 
    this.snapshotStore.getVersions(documentId, (err, versions) => {
      Iif (versions.indexOf(version) >= 0) {
        closestVersion = version
      } else {
        // We don't have a snaphot for that requested version
        let smallerVersions = versions.filter(function(v) {
          return parseInt(v, 10) < version
        })
        // Take the closest version if there is any
        closestVersion = Math.max.apply(null, smallerVersions)
      }
      Iif (!closestVersion) {
        return cb(null, undefined)
      }
      this.snapshotStore.getSnapshot(documentId, version, cb)
    })
  }
}
 
export default SnapshotEngine