chunk.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. 'use strict'
  2. const assert = require('check-types').assert
  3. const OError = require('@overleaf/o-error')
  4. const History = require('./history')
  5. /**
  6. * @typedef {import("./types").BlobStore} BlobStore
  7. * @typedef {import("./change")} Change
  8. * @typedef {import("./snapshot")} Snapshot
  9. */
  10. /**
  11. * @constructor
  12. * @param {History} history
  13. * @param {number} startVersion
  14. *
  15. * @classdesc
  16. * A Chunk is a {@link History} that is part of a project's overall history. It
  17. * has a start and an end version that place its History in context.
  18. */
  19. function Chunk(history, startVersion) {
  20. assert.instance(history, History, 'bad history')
  21. assert.integer(startVersion, 'bad startVersion')
  22. this.history = history
  23. this.startVersion = startVersion
  24. }
  25. class ConflictingEndVersion extends OError {
  26. constructor(clientEndVersion, latestEndVersion) {
  27. const message =
  28. 'client sent updates with end_version ' +
  29. clientEndVersion +
  30. ' but latest chunk has end_version ' +
  31. latestEndVersion
  32. super(message, { clientEndVersion, latestEndVersion })
  33. this.clientEndVersion = clientEndVersion
  34. this.latestEndVersion = latestEndVersion
  35. }
  36. }
  37. Chunk.ConflictingEndVersion = ConflictingEndVersion
  38. class NotFoundError extends OError {
  39. // `message` and `info` optional arguments allow children classes to override
  40. // these values, ensuring backwards compatibility with previous implementation
  41. // based on the `overleaf-error-type` library
  42. constructor(projectId, message, info) {
  43. const errorMessage = message || `no chunks for project ${projectId}`
  44. const errorInfo = info || { projectId }
  45. super(errorMessage, errorInfo)
  46. this.projectId = projectId
  47. }
  48. }
  49. Chunk.NotFoundError = NotFoundError
  50. class VersionNotFoundError extends NotFoundError {
  51. constructor(projectId, version) {
  52. super(projectId, `chunk for ${projectId} v ${version} not found`, {
  53. projectId,
  54. version,
  55. })
  56. this.projectId = projectId
  57. this.version = version
  58. }
  59. }
  60. Chunk.VersionNotFoundError = VersionNotFoundError
  61. class BeforeTimestampNotFoundError extends NotFoundError {
  62. constructor(projectId, timestamp) {
  63. super(projectId, `chunk for ${projectId} timestamp ${timestamp} not found`)
  64. this.projectId = projectId
  65. this.timestamp = timestamp
  66. }
  67. }
  68. Chunk.BeforeTimestampNotFoundError = BeforeTimestampNotFoundError
  69. class NotPersistedError extends NotFoundError {
  70. constructor(projectId) {
  71. super(projectId, `chunk for ${projectId} not persisted yet`)
  72. this.projectId = projectId
  73. }
  74. }
  75. Chunk.NotPersistedError = NotPersistedError
  76. Chunk.fromRaw = function chunkFromRaw(raw) {
  77. return new Chunk(History.fromRaw(raw.history), raw.startVersion)
  78. }
  79. Chunk.prototype.toRaw = function chunkToRaw() {
  80. return { history: this.history.toRaw(), startVersion: this.startVersion }
  81. }
  82. /**
  83. * The history for this chunk.
  84. *
  85. * @return {History}
  86. */
  87. Chunk.prototype.getHistory = function () {
  88. return this.history
  89. }
  90. /**
  91. * {@see History#getSnapshot}
  92. * @return {Snapshot}
  93. */
  94. Chunk.prototype.getSnapshot = function () {
  95. return this.history.getSnapshot()
  96. }
  97. /**
  98. * {@see History#getChanges}
  99. * @return {Array.<Change>}
  100. */
  101. Chunk.prototype.getChanges = function () {
  102. return this.history.getChanges()
  103. }
  104. /**
  105. * {@see History#pushChanges}
  106. * @param {Array.<Change>} changes
  107. */
  108. Chunk.prototype.pushChanges = function chunkPushChanges(changes) {
  109. this.history.pushChanges(changes)
  110. }
  111. /**
  112. * The version of the project after applying all changes in this chunk.
  113. *
  114. * @return {number} non-negative, greater than or equal to start version
  115. */
  116. Chunk.prototype.getEndVersion = function chunkGetEndVersion() {
  117. return this.startVersion + this.history.countChanges()
  118. }
  119. /**
  120. * The timestamp of the last change in this chunk
  121. */
  122. Chunk.prototype.getEndTimestamp = function getEndTimestamp() {
  123. if (!this.history.countChanges()) return null
  124. return this.history.getChanges().slice(-1)[0].getTimestamp()
  125. }
  126. /**
  127. * The version of the project before applying all changes in this chunk.
  128. *
  129. * @return {number} non-negative, less than or equal to end version
  130. */
  131. Chunk.prototype.getStartVersion = function () {
  132. return this.startVersion
  133. }
  134. /**
  135. * {@see History#loadFiles}
  136. *
  137. * @param {string} kind
  138. * @param {BlobStore} blobStore
  139. * @return {Promise}
  140. */
  141. Chunk.prototype.loadFiles = function chunkLoadFiles(kind, blobStore) {
  142. return this.history.loadFiles(kind, blobStore)
  143. }
  144. module.exports = Chunk