Skip to content

Commit

Permalink
v0.68.6
Browse files Browse the repository at this point in the history
  • Loading branch information
xaviergonz committed May 17, 2022
1 parent 25caf87 commit 09c8bd4
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log

## 0.68.6

- Fixed `applySnapshot` generating no-op patches sometimes.

## 0.68.5

- Fixed `fromSnapshotProcessor` not accepting null or undefined when a `tProp` with a default value was used.
Expand Down
2 changes: 1 addition & 1 deletion packages/lib/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mobx-keystone",
"version": "0.68.5",
"version": "0.68.6",
"description": "A MobX powered state management solution based on data trees with first class support for TypeScript, snapshots, patches and much more",
"keywords": [
"mobx",
Expand Down
8 changes: 6 additions & 2 deletions packages/lib/src/snapshot/reconcileModelSnapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { isReservedModelKey, modelIdKey, modelTypeKey } from "../model/metadata"
import { isModel, isModelSnapshot } from "../model/utils"
import type { ModelClass } from "../modelShared/BaseModelShared"
import { getModelInfoForName } from "../modelShared/modelInfo"
import { deepEquals } from "../treeUtils/deepEquals"
import { runTypeCheckingAfterChange } from "../tweaker/typeChecking"
import { withoutTypeChecking } from "../tweaker/withoutTypeChecking"
import { failure, isArray } from "../utils"
Expand Down Expand Up @@ -49,8 +50,11 @@ function reconcileModelSnapshot(
return fromSnapshot<AnyModel>(sn)
}
} else if (isArray(parent)) {
// no id inside an array, no reconciliation possible
return fromSnapshot<AnyModel>(sn)
// no id and inside an array? no reconciliation possible,
// unless the snapshots are equivalent (note deep equals will use the snapshot of value auto)
if (!deepEquals(value, sn)) {
return fromSnapshot<AnyModel>(sn)
}
}

const modelObj: AnyModel = value
Expand Down
7 changes: 7 additions & 0 deletions packages/lib/src/snapshot/reconcileSnapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { isModel } from "../model/utils"
import { fastGetParentPathIncludingDataObjects } from "../parent"
import { failure, isMap, isPrimitive, isSet } from "../utils"
import type { ModelPool } from "../utils/ModelPool"
import { getSnapshot } from "./getSnapshot"
import { registerDefaultReconcilers } from "./registerDefaultReconcilers"

type Reconciler = (value: any, sn: any, modelPool: ModelPool, parent: any) => any | undefined
Expand All @@ -26,6 +27,12 @@ export function reconcileSnapshot(value: any, sn: any, modelPool: ModelPool, par
return sn
}

// if the snapshot passed is exactly the same as the current one
// then it is already reconciled
if (getSnapshot(value) === sn) {
return value
}

registerDefaultReconcilers()

const reconcilersLen = reconcilers.length
Expand Down
33 changes: 33 additions & 0 deletions packages/lib/test/ref/rootRef.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
Ref,
rootRef,
runUnprotected,
tProp,
types,
undoMiddleware,
} from "../../src"
import { autoDispose } from "../utils"
Expand Down Expand Up @@ -807,3 +809,34 @@ test("generic typings", () => {
// @ts-expect-error
genericRef2(new GenericModel({ v1: 1, v2: "2" }))
})

test("issue #456", () => {
@model("issue #456/Todo")
class Todo extends Model({
id: idProp,
text: tProp(types.string, ""),
}) {}

const todoRef = rootRef<Todo>("issue #456/TodoRef")

@model("issue #456/TodoList")
class TodoList extends Model({
todos: tProp(types.array(Todo)),
selectedRef: tProp(types.ref(todoRef)),
selectedRefs: tProp(types.array(types.ref(todoRef))),
}) {}

const todoList = new TodoList({
todos: [new Todo({ id: "todo1" })],
selectedRef: todoRef("todo1"),
selectedRefs: [todoRef("todo1")],
})

const patches: Patch[][] = []

onPatches(todoList, (p) => patches.push(p))
const sn = getSnapshot(todoList)
applySnapshot(todoList, sn)

expect(patches).toHaveLength(0)
})
13 changes: 7 additions & 6 deletions packages/lib/test/snapshot/snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ test("id-less reconciliation", () => {
let id = 0

@model("idlr/i")
class I extends Model({}) {
class I extends Model({ x: prop(0) }) {
id = id++
}

Expand All @@ -590,15 +590,16 @@ test("id-less reconciliation", () => {
applySnapshot(
r,
modelSnapshotOutWithMetadata(R, {
arr: [modelSnapshotOutWithMetadata(I, {}), modelSnapshotOutWithMetadata(I, {})],
m: modelSnapshotOutWithMetadata(I, {}),
arr: [modelSnapshotOutWithMetadata(I, { x: 0 }), modelSnapshotOutWithMetadata(I, { x: 1 })],
m: modelSnapshotOutWithMetadata(I, { x: 0 }),
})
)

expect(r.m.id).toBe(2)
// no reconciliation inside an array
expect(r.arr[0].id).toBe(3)
expect(r.arr[1].id).toBe(4)
expect(r.arr[0].id).toBe(0)
// no reconciliation inside an array if data is different
// (in this case x is 1)
expect(r.arr[1].id).toBe(3)
})

test("id-full reconciliation", () => {
Expand Down

0 comments on commit 09c8bd4

Please sign in to comment.