Expand all

ve.dm.TransactionSquasher

Constructor

new ve.dm.TransactionSquasher(transaction) #

Squasher to create one transaction from multiple transactions applicable in turn

The squashed transaction has the same effect on a document as applying the original transactions in turn, but it may cause rebase conflicts where the original sequence of transactions would not have.

Suppose we have linmod arrays A, B, C, D. Note that (x,A->B,m) then (x,C->D,n) becomes (x,A.concat(C*)->D.concat(B*),min(m,n)) Where len = min(B.length, C.length) and C*=C.slice(len) and B*=B.slice(len). I.e. "A->B then C->D" becomes "remove A, remove C*, insert D, insert B*". Examples: 1234Aa5678 (4,Aa->Bb,4) 1234Bb5678 (4,B->D,5) 1234Db5678 --> (4,Aa->Db,4) 1234Aa5678 (4,Aa->Bb,4) 1234Bb5678 (4,Bb5->Dd,3) 1234Dd678 --> (4,Aa5->Dd,3)

The same sort of thing happens if the starts are not the same, e.g. helloworld (2,ll>LL,1,wo>WO,3) heLLoWOrld (3,LoW>HI,4) heLHIrld --> (2,llowo>LHI,3) hiwed (1,i>ello,1,e>orl,1) helloworld (2,llowor>a,2) heald --> (1,iwe>eal,1)

However, removal followed by reinsertion cannot be stripped out entirely, because then the squashed transaction, considered as a partial function between documents, would have a larger preimage than the composition of the original transactions. This can probably break things like associativity). Example:

hello! (1,ello>iworld,1) hiworld! (1,i>ello,6) helloworld! --> (1,ello>elloworld,1)

For annotations in the follow-up transaction, two forms of processing are needed: annotating previously-inserted content, and adding the annotations operation into the transaction for retained ranges.

Parameters:

Name Type Description
transaction ve.dm.Transaction

Base transaction to clone then squash others onto

Source:

Squasher to create one transaction from multiple transactions applicable in turn

The squashed transaction has the same effect on a document as applying the original transactions in turn, but it may cause rebase conflicts where the original sequence of transactions would not have.

Properties

attributeOperations #

Properties:

Name Type Description
attributeOperations Object

During squashIn, live references to attribute operations at current offset, keyed by attribute name, or null if at an open element

Source:

globalOffset #

Properties:

Name Type Description
globalOffset number

During squashIn, global offset over all operations

Source:

index #

Properties:

Name Type Description
index number

During squashIn, index of current op within operations

Source:

offset #

During squashIn, post-transaction offset within the current op

Properties:

Name Type Description
offset number

During squashIn, post-tx linmod offset within current op. "Post transaction" means that for replacements, the offset is within the insert block. The reason we care about post-transaction offsets is that the match the pre-transaction offsets of the next transaction.

Source:
During squashIn, post-transaction offset within the current op

op #

Properties:

Name Type Description
op Object

During squashIn, the current op within operations

Source:

operations #

Properties:

Name Type Description
operations Array.<Object>

Reference to .operations within the tx

Source:

transaction #

Properties:

Name Type Description
transaction ve.dm.Transaction

Transaction being squashed together

Source:

Methods

changeElement(openElement, key, from, to)private #

Change an attribute in an open element

Parameters:

Name Type Description
openElement Object

The open element

key string

The attribute name

from any

Old value, or undefined if the attribute is being created

to any

New value, or undefined if the attribute is being removed

Source:
Change an attribute in an open element

getTransaction() → {ve.dm.Transaction} #

Get the Transaction as-is

Source:

Returns:

The transaction

Type
ve.dm.Transaction
Get the Transaction as-is

normalizePosition()private #

Normalize .index, .offset and .op so we're not at the end of a replace/retain

Source:
Normalize .index, .offset and .op so we're not at the end of a replace/retain

processAttribute(key, from, to)private #

Process the setting of an attribute

The case from === to is possible. An identity attribute change still proves there is an open element at this position, so cannot be stripped

Parameters:

Name Type Description
key string

The attribute key

from any

The old value

to any

The new value

Source:

Process the setting of an attribute

The case from === to is possible.

processInsert(items) → {number}private #

Process the insertion of some items, stopping part-way if convenient

If some of the insertion is undoing a removal in this.transaction, then the "cancelled" content effectively becomes part of an identity replacement: replace 'foo' with 'foo'. (The content cannot be stripped out entirely from the squashed transaction, because then the squashed transaction, considered as a partial function between documents, would have a larger preimage than the composition of the original transactions. This can probably break things like associativity).

Parameters:

Name Type Description
items Array.<Object>

Items to insert some of

Source:

Returns:

The length of the initial slice of items that was inserted

Type
number

Process the insertion of some items, stopping part-way if convenient

If some of the insertion is undoing a removal in this.transaction, then the "cancelled" content effectively becomes part of an identity replacement: replace 'foo' with 'foo'.

processRemove(items) → {number}private #

Process the removal of some items, stopping part-way if convenient

If some of the removal is undoing an insertion in this.transaction, then the "cancelled" content is stripped out entirely from the squashed transaction.

Parameters:

Name Type Description
items Array.<Object>

Items to remove some of; can be modified in place (annotated)

Source:

Returns:

The length of the initial slice of items that was removed

Type
number

Process the removal of some items, stopping part-way if convenient

If some of the removal is undoing an insertion in this.transaction, then the "cancelled" content is stripped out entirely from the squashed transaction.

processRetain(maxLength) → {number}private #

Process the retention of content, stopping part-way if convenient

Parameters:

Name Type Description
maxLength number

The maximum amount of content to retain

Source:

Returns:

The amount of content retained

Type
number
Process the retention of content, stopping part-way if convenient

readAttributes()private #

Read the open element at the current offset (if any)

Sets this.openElement to the open element (or null) Sets this.attribute to an object containing attribute key-values (or {})

Source:

Read the open element at the current offset (if any)

Sets this.openElement to the open element (or null) Sets this.attribute to an object containing attribute key-values (or {})

splitIfInterior()private #

If in the interior of a retain operation, split it here without moving.

For retain, the length is split at the current offset (throws an error if at the end) For all other operations, throws an error if not at the start

Afterwards, this.offset is guaranteed to be 0.

Source:
If in the interior of a retain operation, split it here without moving.

squashIn(tx) #

Modify our Transaction in-place to incorporate a follow-up transaction

Applying the modified transaction has the same effect as applying the original transaction then the follow-up, but it may cause rebase conflicts where the original pair of transactions would not have.

Parameters:

Name Type Description
tx ve.dm.Transaction

Follow-up transaction (that can apply immediately after this)

Source:

Modify our Transaction in-place to incorporate a follow-up transaction

Applying the modified transaction has the same effect as applying the original transaction then the follow-up, but it may cause rebase conflicts where the original pair of transactions would not have.

tryUnsplit()private #

If this operation and the previous one are retains, join them

Source:
If this operation and the previous one are retains, join them

equalItems(item1, item2) → {boolean}static #

Test whether two linmod items have equal values

Parameters:

Name Type Description
item1 any

A data item

item2 any

Another data item

Source:

Returns:

Whether the items have equal values

Type
boolean
Test whether two linmod items have equal values

squash(transactions) → {ve.dm.Transaction}static #

Squash an array of consecutive transactions into a single transaction

Parameters:

Name Type Description
transactions Array.<ve.dm.Transaction>

Non-empty array of consecutive transactions

Source:

Returns:

Single transaction with the same content as the transaction array

Type
ve.dm.Transaction
Squash an array of consecutive transactions into a single transaction