Skip to content

Commit

Permalink
Order of patches based on internal mutation coun (#52)
Browse files Browse the repository at this point in the history
* Order of patches based on internal mutation coun

* Version bump
  • Loading branch information
vladnicula authored Dec 5, 2023
1 parent ba39a7e commit f9cd4d3
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 25 deletions.
30 changes: 25 additions & 5 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,32 @@ export declare class MutationsManager {
mutationMaps: Map<ObjectTree, ProxyMapType<ObjectTree>>;
mutationDirtyPaths: Map<ObjectTree, Set<ProxyMutationObjectHandler<ObjectTree>>>;
mutationSelectorPointers: Map<ObjectTree, Array<SelectorTreeBranch>>;
mutationChagnePointers: Map<ObjectTree, MutationTreeNode>;
mutationChangePointers: Map<ObjectTree, MutationTreeNode>;
private getSubProxy;
startMutation(target: ObjectTree): void;
hasRoot(rootA: any): boolean;
commit(target: ObjectTree): JSONPatchEnhanced[];
mutate<T extends ObjectTree>(target: T, callback: (mutable: T) => unknown): JSONPatchEnhanced[] | undefined;
commit(target: ObjectTree): {
op: "replace" | "remove" | "add";
path: string;
value: unknown;
old?: unknown;
pathArray: string[];
}[];
mutate<T extends ObjectTree>(target: T, callback: (mutable: T) => unknown): {
op: "replace" | "remove" | "add";
path: string;
value: unknown;
old?: unknown;
pathArray: string[];
}[] | undefined;
}
export declare const mutate: <T extends object>(stateTree: T, callback: (mutable: T) => unknown) => JSONPatchEnhanced[] | undefined;
export declare const mutate: <T extends object>(stateTree: T, callback: (mutable: T) => unknown) => {
op: 'replace' | 'remove' | 'add';
path: string;
value: unknown;
old?: unknown;
pathArray: string[];
}[] | undefined;
export declare const autorun: <T extends object>(stateTree: T, callback: (observable: T, patches?: JSONPatchEnhanced[] | undefined) => unknown) => () => void;
/**
* When working with domain objects, it's probably best to have a
Expand Down Expand Up @@ -57,12 +75,14 @@ export declare class ProxyMutationObjectHandler<T extends object> {
readonly selectorPointerArray: Array<SelectorTreeBranch>;
readonly writeSelectorPointerArray: Array<SelectorTreeBranch>;
mutationNode: MutationTreeNode;
incOpCount: () => number;
constructor(params: {
mutationNode: MutationTreeNode;
target: T;
selectorPointerArray: Array<SelectorTreeBranch>;
dirtyPaths: Set<ProxyMutationObjectHandler<ObjectTree>>;
proxyfyAccess: ProxyAccessFN;
incOpCount: () => number;
});
get<K extends keyof T>(target: T, prop: K): any;
set<K extends keyof T>(target: T, prop: K, value: T[K]): boolean;
Expand Down Expand Up @@ -104,5 +124,5 @@ export declare const select: <T extends object, MP extends SelectorMappingBase<T
dispose: () => void;
};
export declare const inversePatch: (patch: JSONPatchEnhanced) => JSONPatchEnhanced;
export declare const LIB_VERSION = "2.0.3beta";
export declare const LIB_VERSION = "2.0.4beta";
export {};
2 changes: 1 addition & 1 deletion dist/index.main.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.module.js

Large diffs are not rendered by default.

17 changes: 14 additions & 3 deletions dist/mutation-map.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ export interface MutationTreeNodeWithReplace {
old: unknown;
/** new value is again, probably falsy, but still exists */
new: unknown;
opCount: number;
}
export interface MutationTreeNodeWithRemove {
/** operation remove old contains old value */
op: "remove";
/** old value ca be fasly, but still exists */
old: unknown;
opCount: number;
}
export interface MutationTreeNodeWithAdd {
/** operation add only contains a new value */
op: "add";
/** new value is can be falsy, but still exists */
new: any;
opCount: number;
}
export declare type MutationTreeNode = ({} | MutationTreeNodeWithReplace | MutationTreeNodeWithRemove | MutationTreeNodeWithAdd) & {
k: string | number;
Expand All @@ -44,6 +47,14 @@ export declare type MutationTreeNode = ({} | MutationTreeNodeWithReplace | Mutat
*/
export declare const getParentWithOperation: (mutationNode: MutationTreeNode) => [MutationTreeNode, string[]] | null;
export declare const makeAndGetChildPointer: (mutationNode: MutationTreeNode, prop: string | number) => MutationTreeNode;
export declare const createMutaitonInMutationTree: (mutationNode: MutationTreeNode, oldValue: unknown, newValue: unknown) => void;
export declare const getPatchesFromMutationTree: (mutationNode: MutationTreeNode) => JSONPatchEnhanced[];
export declare const accumulatePatchesFromMutationTree: (mutationNode: MutationTreeNode, acc: JSONPatchEnhanced[], pathArray?: string[]) => void;
export declare const createMutaitonInMutationTree: (mutationNode: MutationTreeNode, oldValue: unknown, newValue: unknown, opCount: number) => void;
export declare const getPatchesFromMutationTree: (mutationNode: MutationTreeNode) => {
op: "replace" | "remove" | "add";
path: string;
value: unknown;
old?: unknown;
pathArray: string[];
}[];
export declare const accumulatePatchesFromMutationTree: (mutationNode: MutationTreeNode, acc: Array<JSONPatchEnhanced & {
opCount: number;
}>, pathArray?: string[]) => void;
30 changes: 22 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,15 @@ export class MutationsManager {
mutationMaps: Map<ObjectTree, ProxyMapType<ObjectTree>> = new Map()
mutationDirtyPaths: Map<ObjectTree, Set<ProxyMutationObjectHandler<ObjectTree>>> = new Map()
mutationSelectorPointers: Map<ObjectTree, Array<SelectorTreeBranch>> = new Map()
mutationChagnePointers: Map<ObjectTree, MutationTreeNode> = new Map()
mutationChangePointers: Map<ObjectTree, MutationTreeNode> = new Map()

private getSubProxy = <T extends ObjectTree>(
target: ObjectTree,
relevantMutationPointer: MutationTreeNode,
selectorTreePointer: Array<SelectorTreeBranch>,
subTarget: T,
// currentPathArray: string[],
incOpCount: () => number
): T => {
const mutationProxies = this.mutationMaps.get(target)
let proxy = mutationProxies?.get(subTarget) as T | undefined
Expand All @@ -115,6 +116,7 @@ export class MutationsManager {
selectorPointerArray: selectorTreePointer,
mutationNode: relevantMutationPointer,
dirtyPaths: this.mutationDirtyPaths.get(target) as Set<ProxyMutationObjectHandler<object>>,
incOpCount: incOpCount,
// pathArray: currentPathArray,
proxyfyAccess: <T extends ObjectTree>(
subentityFromTarget: T,
Expand All @@ -128,6 +130,7 @@ export class MutationsManager {
relevantSelectionPointers,
subentityFromTarget,
// someOtherPathArray
incOpCount
)
}
}) as ProxyHandler<T>) as T
Expand All @@ -149,14 +152,20 @@ export class MutationsManager {
p: null,
k: ''
}
this.mutationChagnePointers.set(target, mutationPointer)
this.mutationChangePointers.set(target, mutationPointer)
let opCount = 0
const incOpCount = () => {
opCount += 1
return opCount
}
const rootProxy = new Proxy(target, new ProxyMutationObjectHandler({
target,
selectorPointerArray: selectorPointers,
mutationNode: mutationPointer,
dirtyPaths: mutationDirtyPaths,
incOpCount: incOpCount,
proxyfyAccess: <T extends ObjectTree>(subTarget: T, mutationPoiner: MutationTreeNode, newPointers: SelectorTreeBranch[]) => {
return this.getSubProxy(target, mutationPoiner, newPointers, subTarget)
return this.getSubProxy(target, mutationPoiner, newPointers, subTarget, incOpCount)
}
}))
proxyMapForMutation.set(target, rootProxy)
Expand Down Expand Up @@ -194,7 +203,7 @@ export class MutationsManager {


// const combinedPatches = combinedJSONPatches(allDistinctPatches)
const combinedPatches = getPatchesFromMutationTree(this.mutationChagnePointers.get(target)!)
const combinedPatches = getPatchesFromMutationTree(this.mutationChangePointers.get(target)!)
selectorsManager.runSelectorPointers(target, uniqueSelectorPaths, combinedPatches)

this.mutationMaps.delete(target)
Expand Down Expand Up @@ -416,14 +425,16 @@ export class ProxyMutationObjectHandler<T extends object> {


mutationNode: MutationTreeNode
incOpCount: () => number

constructor (params: {
mutationNode: MutationTreeNode,
target: T,
// pathArray: string []
selectorPointerArray: Array<SelectorTreeBranch>,
dirtyPaths: Set<ProxyMutationObjectHandler<ObjectTree>>,
proxyfyAccess: ProxyAccessFN
proxyfyAccess: ProxyAccessFN,
incOpCount: () => number
}) {
const { target, proxyfyAccess, dirtyPaths} = params
// this.pathArray = pathArray
Expand All @@ -432,6 +443,7 @@ export class ProxyMutationObjectHandler<T extends object> {
this.dirtyPaths = dirtyPaths
this.selectorPointerArray = params.selectorPointerArray
this.mutationNode = params.mutationNode
this.incOpCount = params.incOpCount
}

get <K extends keyof T>(target: T, prop: K) {
Expand Down Expand Up @@ -584,7 +596,8 @@ export class ProxyMutationObjectHandler<T extends object> {
childMutationPointer,
// if prop exists in target, we replace, otherwise we spcify NO_VALUE
prop in target ? target[prop] : NO_VALUE,
opValue
opValue,
this.incOpCount()
)

/**
Expand Down Expand Up @@ -629,7 +642,8 @@ export class ProxyMutationObjectHandler<T extends object> {
createMutaitonInMutationTree(
childMutationPointer,
target[prop],
NO_VALUE
NO_VALUE,
this.incOpCount()
)

this.dirtyPaths.add(this)
Expand Down Expand Up @@ -845,4 +859,4 @@ export const inversePatch = (patch: JSONPatchEnhanced): JSONPatchEnhanced => {
}
}

export const LIB_VERSION = '2.0.3beta'
export const LIB_VERSION = '2.0.4beta'
23 changes: 18 additions & 5 deletions src/mutation-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,24 @@ export interface MutationTreeNodeWithReplace {
/** replace has an old value, which might be falsy, but still exists */
old: unknown,
/** new value is again, probably falsy, but still exists */
new: unknown
new: unknown,
opCount: number
}

export interface MutationTreeNodeWithRemove {
/** operation remove old contains old value */
op: "remove",
/** old value ca be fasly, but still exists */
old: unknown
opCount: number
}

export interface MutationTreeNodeWithAdd {
/** operation add only contains a new value */
op: "add",
/** new value is can be falsy, but still exists */
new: any
opCount: number
}

export type MutationTreeNode = ( {} | MutationTreeNodeWithReplace | MutationTreeNodeWithRemove | MutationTreeNodeWithAdd) & {
Expand Down Expand Up @@ -100,7 +103,8 @@ export const makeAndGetChildPointer = (mutationNode: MutationTreeNode, prop: str
export const createMutaitonInMutationTree = (
mutationNode: MutationTreeNode,
oldValue: unknown,
newValue: unknown
newValue: unknown,
opCount: number
) => {
// 1. check if this node contains an operation
if ( "op" in mutationNode ) {
Expand Down Expand Up @@ -180,6 +184,7 @@ export const createMutaitonInMutationTree = (

Object.assign(mutationNode, {
op,
opCount,
d: true, // TODO remove
...(oldValue !== NO_VALUE? {old: oldValue} : {}),
...(newValue !== NO_VALUE? {new: newValue} : {}),
Expand Down Expand Up @@ -303,18 +308,26 @@ const recursiveApplyChanges = (mutationNode: MutationTreeNode) => {


export const getPatchesFromMutationTree = (mutationNode: MutationTreeNode) => {
const patches: JSONPatchEnhanced[] = []
const patches: Array<JSONPatchEnhanced & {opCount : number }> = []
accumulatePatchesFromMutationTree(mutationNode, patches)
return patches
return patches.sort((a, b) => a.opCount - b.opCount).map((patch) => {
const { opCount, ...rest } = patch
return rest
})
}

export const accumulatePatchesFromMutationTree = (mutationNode: MutationTreeNode, acc: JSONPatchEnhanced[], pathArray: string[] = []) => {
export const accumulatePatchesFromMutationTree = (
mutationNode: MutationTreeNode,
acc: Array<JSONPatchEnhanced & {opCount : number }>,
pathArray: string[] = []
) => {
if ("op" in mutationNode ) {
acc.push({
op: mutationNode.op,
old: ('old' in mutationNode) ? mutationNode.old : undefined,
value: ('new' in mutationNode) ? mutationNode.new : undefined,
pathArray,
opCount: mutationNode.opCount,
path: `/${pathArray.join('/')}`
})
return
Expand Down
8 changes: 6 additions & 2 deletions tests/mutate-patch-order.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@ describe.only('patch order from mutations', () => {
parentId: 'a'
}
const patches = mutate(document, (modifiable) => {
modifiable.nodes.c = newNodeC
modifiable.nodes[newNodeC.parentId].children[newNodeC.id] = true
// order of the operations is important
// the const parent here is needed before
// the change is made
const parent = modifiable.nodes[newNodeC.parentId]
modifiable.nodes[newNodeC.id] = newNodeC
parent.children[newNodeC.id] = true
})

console.log('patches', patches)
Expand Down

0 comments on commit f9cd4d3

Please sign in to comment.