Przeglądaj źródła

Compress adjacent inserts and deletes into one diff item

James Allen 12 lat temu
rodzic
commit
575afae048

+ 17 - 0
services/track-changes/app/coffee/DiffGenerator.coffee

@@ -35,8 +35,25 @@ module.exports = DiffGenerator =
 		diff = [ u: initialContent ]
 		for update in updates
 			diff = DiffGenerator.applyUpdateToDiff diff, update
+		diff = DiffGenerator.compressDiff diff
 		return diff
 
+	compressDiff: (diff) ->
+		newDiff = []
+		for part in diff
+			lastPart = newDiff[newDiff.length - 1]
+			if lastPart? and lastPart.i? and part.i? and lastPart.meta.user_id == part.meta.user_id
+				lastPart.i += part.i
+				lastPart.meta.start_ts = Math.min(lastPart.meta.start_ts, part.meta.start_ts)
+				lastPart.meta.end_ts = Math.max(lastPart.meta.end_ts, part.meta.end_ts)
+			else if lastPart? and lastPart.d? and part.d? and lastPart.meta.user_id == part.meta.user_id
+				lastPart.d += part.d
+				lastPart.meta.start_ts = Math.min(lastPart.meta.start_ts, part.meta.start_ts)
+				lastPart.meta.end_ts = Math.max(lastPart.meta.end_ts, part.meta.end_ts)
+			else
+				newDiff.push part
+		return newDiff
+
 	applyOpToDiff: (diff, op, meta) ->
 		position = 0
 

+ 1 - 2
services/track-changes/test/acceptance/coffee/GettingADiffTests.coffee

@@ -51,8 +51,7 @@ describe "Getting a diff", ->
 		@lines = ["one two three four"]
 		@expected_diff = [
 			{ u: "one " }
-			{ i: "two ", meta: { start_ts: @from + twoMinutes, end_ts: @from + twoMinutes, user: @user } }
-			{ i: "three ", meta: { start_ts: @to - twoMinutes, end_ts: @to - twoMinutes, user: @user } }
+			{ i: "two three ", meta: { start_ts: @from + twoMinutes, end_ts: @to - twoMinutes, user: @user } }
 		]
 
 		MockDocUpdaterApi.docs[@doc_id] =

+ 46 - 0
services/track-changes/test/unit/coffee/DiffGenerator/DiffGeneratorTests.coffee

@@ -10,6 +10,7 @@ describe "DiffGenerator", ->
 		@DiffGenerator = SandboxedModule.require modulePath
 		@ts = Date.now()
 		@user_id = "mock-user-id"
+		@user_id_2 = "mock-user-id-2"
 		@meta = {
 			start_ts: @ts, end_ts: @ts, user_id: @user_id
 		}
@@ -62,6 +63,7 @@ describe "DiffGenerator", ->
 				{ i: "mock-update-3" }
 			]
 			@DiffGenerator.applyUpdateToDiff = sinon.stub().returns(@diff)
+			@DiffGenerator.compressDiff = sinon.stub().returns(@diff)
 			@result = @DiffGenerator.buildDiff(@content, @updates)
 
 		it "should return the diff", ->
@@ -80,6 +82,50 @@ describe "DiffGenerator", ->
 					.calledWith(sinon.match.any, update)
 					.should.equal true
 
+		it "should compress the diff", ->
+			@DiffGenerator.compressDiff
+				.calledWith(@diff)
+				.should.equal true
+
+	describe "compressDiff", ->
+		describe "with adjacent inserts with the same user_id", ->
+			it "should create one update with combined meta data and min/max timestamps", ->
+				diff = @DiffGenerator.compressDiff([
+					{ i: "foo", meta: { start_ts: 10, end_ts: 20, user_id: @user_id }}
+					{ i: "bar", meta: { start_ts: 5,  end_ts: 15, user_id: @user_id }}
+				])
+				expect(diff).to.deep.equal([
+					{ i: "foobar", meta: { start_ts: 5, end_ts: 20, user_id: @user_id }}
+				])
+
+		describe "with adjacent inserts with different user_ids", ->
+			it "should leave the inserts unchanged", ->
+				input = [
+					{ i: "foo", meta: { start_ts: 10, end_ts: 20, user_id: @user_id }}
+					{ i: "bar", meta: { start_ts: 5,  end_ts: 15, user_id: @user_id_2 }}
+				]
+				output = @DiffGenerator.compressDiff(input)
+				expect(output).to.deep.equal(input)
+
+		describe "with adjacent deletes with the same user_id", ->
+			it "should create one update with combined meta data and min/max timestamps", ->
+				diff = @DiffGenerator.compressDiff([
+					{ d: "foo", meta: { start_ts: 10, end_ts: 20, user_id: @user_id }}
+					{ d: "bar", meta: { start_ts: 5,  end_ts: 15, user_id: @user_id }}
+				])
+				expect(diff).to.deep.equal([
+					{ d: "foobar", meta: { start_ts: 5, end_ts: 20, user_id: @user_id }}
+				])
+
+		describe "with adjacent deletes with different user_ids", ->
+			it "should leave the deletes unchanged", ->
+				input = [
+					{ d: "foo", meta: { start_ts: 10, end_ts: 20, user_id: @user_id }}
+					{ d: "bar", meta: { start_ts: 5,  end_ts: 15, user_id: @user_id_2 }}
+				]
+				output = @DiffGenerator.compressDiff(input)
+				expect(output).to.deep.equal(input)
+
 	describe "applyUpdateToDiff", ->
 		describe "an insert", ->
 			it "should insert into the middle of (u)nchanged text", ->