All files / json-crdt/partial-edit PartialEdit.ts

83.33% Statements 45/54
60% Branches 3/5
80% Functions 8/10
82.35% Lines 42/51

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 86 87 88 89 90 91 92 93 94 95 96 97 98  1x       1x       1x   2x 2x     2x 2x 2x       3x 3x 3x 3x 8x 8x 8x 6x       6x 6x 5x 5x           2x       2x 2x       3x       2x 2x 2x 2x 2x 2x           2x 2x 2x 2x 2x 2x 2x 2x 2x 2x   2x             1x                            
import type {Patch} from '../../json-crdt-patch';
import {ClockTable} from '../../json-crdt-patch/codec/clock/ClockTable';
import type {Decoder} from '../codec/indexed/binary/Decoder';
import type {Encoder} from '../codec/indexed/binary/Encoder';
import type {IndexedFields, FieldName, IndexedNodeFields} from '../codec/indexed/binary/types';
import {PartialEditModel} from './PartialEditModel';
import type {IJsonCrdtPatchEditOperation} from '../../json-crdt-patch/types';
import type {FieldEdits} from './types';
 
export class PartialEdit {
  /** List of fields/nodes to fetch before applying the patches. */
  loadList = new Set<string>();
  doc: PartialEditModel | null = null;
 
  constructor(
    protected readonly decoder: Decoder,
    protected readonly encoder: Encoder,
    public readonly clockTable: ClockTable = new ClockTable(),
  ) {}
 
  public populateLoadList(patch: Patch): void {
    const ops = patch.ops;
    const length = ops.length;
    const loadList = this.loadList;
    for (let i = 0; i < length; i++) {
      const op = ops[i];
      const obj = (op as Partial<IJsonCrdtPatchEditOperation>).obj;
      if (obj) {
        Iif (obj.sid === 0) {
          loadList.add('r');
          continue;
        }
        const entry = this.clockTable.bySid.get(obj.sid);
        if (!entry) continue;
        const fieldName: FieldName = `${entry.index.toString(36)}_${obj.time.toString(36)}`;
        loadList.add(fieldName);
      }
    }
  }
 
  public getFieldsToLoad(): Set<string> {
    return this.loadList;
  }
 
  public loadPartialModel(fields: IndexedNodeFields): PartialEditModel {
    this.doc = this.decoder.decodeFields(this.clockTable, fields, PartialEditModel);
    return this.doc;
  }
 
  public applyPatch(patch: Patch) {
    this.doc!.applyPatch(patch);
  }
 
  public populateClockTable(): void {
    const doc = this.doc!;
    const peers = doc.clock.peers;
    const clockTable = this.clockTable;
    peers.forEach((clock, sid) => {
      if (!clockTable.bySid.has(sid)) {
        clockTable.push(clock);
      }
    });
  }
 
  public getFieldEdits(): FieldEdits {
    const doc = this.doc!;
    const updates = this.encoder.encode(doc, this.clockTable);
    const clockTable = this.clockTable;
    const deletedIds = doc.deletes;
    const length = deletedIds.length;
    const deletes = new Set<FieldName>();
    for (let i = 0; i < length; i++) {
      const id = deletedIds[i];
      const field: FieldName = `${clockTable.getBySid(id.sid).index}_${id.time.toString(36)}`;
      deletes.add(field);
    }
    return {
      updates,
      deletes,
    };
  }
}
 
export class PartialEditFactory {
  constructor(
    protected readonly decoder: Decoder,
    protected readonly encoder: Encoder,
  ) {}
 
  public startPartialEdit(clockBlob: IndexedFields['c']): PartialEdit {
    const reader = this.decoder.dec.reader;
    reader.reset(clockBlob);
    const clockTable = ClockTable.decode(reader);
    const partialEdit = new PartialEdit(this.decoder, this.encoder, clockTable);
    return partialEdit;
  }
}