history.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. 'use strict'
  2. const assert = require('check-types').assert
  3. const BPromise = require('bluebird')
  4. const Change = require('./change')
  5. const Snapshot = require('./snapshot')
  6. /**
  7. * @typedef {import("./types").BlobStore} BlobStore
  8. */
  9. class History {
  10. /**
  11. * @constructor
  12. * @param {Snapshot} snapshot
  13. * @param {Array.<Change>} changes
  14. *
  15. * @classdesc
  16. * A History is a {@link Snapshot} and a sequence of {@link Change}s that can
  17. * be applied to produce a new snapshot.
  18. */
  19. constructor(snapshot, changes) {
  20. assert.instance(snapshot, Snapshot, 'bad snapshot')
  21. assert.maybe.array.of.instance(changes, Change, 'bad changes')
  22. this.snapshot = snapshot
  23. this.changes = changes || []
  24. }
  25. static fromRaw(raw) {
  26. return new History(
  27. Snapshot.fromRaw(raw.snapshot),
  28. raw.changes.map(Change.fromRaw)
  29. )
  30. }
  31. toRaw() {
  32. function changeToRaw(change) {
  33. return change.toRaw()
  34. }
  35. return {
  36. snapshot: this.snapshot.toRaw(),
  37. changes: this.changes.map(changeToRaw),
  38. }
  39. }
  40. getSnapshot() {
  41. return this.snapshot
  42. }
  43. getChanges() {
  44. return this.changes
  45. }
  46. countChanges() {
  47. return this.changes.length
  48. }
  49. /**
  50. * Add changes to this history.
  51. *
  52. * @param {Array.<Change>} changes
  53. */
  54. pushChanges(changes) {
  55. this.changes.push.apply(this.changes, changes)
  56. }
  57. /**
  58. * If this History references blob hashes, either in the Snapshot or the
  59. * Changes, add them to the given set.
  60. *
  61. * @param {Set.<String>} blobHashes
  62. */
  63. findBlobHashes(blobHashes) {
  64. function findChangeBlobHashes(change) {
  65. change.findBlobHashes(blobHashes)
  66. }
  67. this.snapshot.findBlobHashes(blobHashes)
  68. this.changes.forEach(findChangeBlobHashes)
  69. }
  70. /**
  71. * If this History contains any File objects, load them.
  72. *
  73. * @param {string} kind see {File#load}
  74. * @param {BlobStore} blobStore
  75. * @return {Promise}
  76. */
  77. loadFiles(kind, blobStore) {
  78. function loadChangeFiles(change) {
  79. return change.loadFiles(kind, blobStore)
  80. }
  81. return BPromise.join(
  82. this.snapshot.loadFiles(kind, blobStore),
  83. BPromise.each(this.changes, loadChangeFiles)
  84. )
  85. }
  86. /**
  87. * Return a version of this history that is suitable for long term storage.
  88. * This requires that we store the content of file objects in the provided
  89. * blobStore.
  90. *
  91. * @param {BlobStore} blobStore
  92. * @param {number} [concurrency] applies separately to files, changes and
  93. * operations
  94. * @return {Promise.<Object>}
  95. */
  96. store(blobStore, concurrency) {
  97. assert.maybe.number(concurrency, 'bad concurrency')
  98. function storeChange(change) {
  99. return change.store(blobStore, concurrency)
  100. }
  101. return BPromise.join(
  102. this.snapshot.store(blobStore, concurrency),
  103. BPromise.map(this.changes, storeChange, { concurrency: concurrency || 1 })
  104. ).then(([rawSnapshot, rawChanges]) => {
  105. return {
  106. snapshot: rawSnapshot,
  107. changes: rawChanges,
  108. }
  109. })
  110. }
  111. }
  112. module.exports = History