teamplay 0.4.0-alpha.26 → 0.4.0-alpha.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/orm/Compat/README.md +46 -6
- package/package.json +2 -2
- package/utils/setDiffDeep.js +28 -15
package/orm/Compat/README.md
CHANGED
|
@@ -353,6 +353,19 @@ for (const $doc of $query) {
|
|
|
353
353
|
}
|
|
354
354
|
```
|
|
355
355
|
|
|
356
|
+
### Mutator Semantics (Core vs Compat)
|
|
357
|
+
|
|
358
|
+
Compatibility mode intentionally aligns mutators with Racer. This differs from core `Signal` behavior.
|
|
359
|
+
|
|
360
|
+
| API | Core (`Signal`) | Compat (`SignalCompat`) |
|
|
361
|
+
| --- | --- | --- |
|
|
362
|
+
| `set` | Uses deep-diff path (`dataTree.set` + internal `setDiffDeep`). | Path-targeted replace semantics, Racer-like. `undefined` keeps delete semantics. |
|
|
363
|
+
| `setEach` | Not a special API in core mutators. | Per-key compat `set` (not `assign` merge/delete behavior). |
|
|
364
|
+
| `setDiffDeep` | Deep-diff engine (`utils/setDiffDeep.js`). | Explicit deep-diff mutator (`SignalCompat.setDiffDeep`) using base deep-diff path. |
|
|
365
|
+
| `setDiff` | N/A as compat shim. | `setDiff(value)` -> base `Signal.set(value)` on current signal. `setDiff(path, value)` -> compat `set(path, value)`. |
|
|
366
|
+
|
|
367
|
+
Migration note: compat behavior is intentionally Racer-aligned and may differ from core mutators.
|
|
368
|
+
|
|
356
369
|
### set(value) and set(path, value)
|
|
357
370
|
|
|
358
371
|
`SignalCompat` accepts both:
|
|
@@ -362,7 +375,14 @@ $.users.user1.name.set('Alice')
|
|
|
362
375
|
$.users.user1.set('profile.name', 'Alice')
|
|
363
376
|
```
|
|
364
377
|
|
|
365
|
-
In compat mode, `set` replaces
|
|
378
|
+
In compat mode, `set` replaces the value at the target path.
|
|
379
|
+
- `set(path, null)` stores `null`.
|
|
380
|
+
- `set(path, undefined)` applies current delete semantics.
|
|
381
|
+
|
|
382
|
+
```js
|
|
383
|
+
await $.users.user1.set('profile', { name: 'Ann', role: 'student' })
|
|
384
|
+
await $.users.user1.set('profile', { name: 'Kate' }) // role is removed
|
|
385
|
+
```
|
|
366
386
|
|
|
367
387
|
### setNull(path?, value)
|
|
368
388
|
|
|
@@ -377,23 +397,43 @@ $.config.setNull('theme', 'light')
|
|
|
377
397
|
Applies a diff-deep update (uses base `Signal.set` internally).
|
|
378
398
|
|
|
379
399
|
```js
|
|
380
|
-
$.users.user1.
|
|
400
|
+
await $.users.user1.set({ profile: { name: 'Ann', role: 'student' } })
|
|
401
|
+
await $.users.user1.setDiffDeep({ profile: { name: 'Kate' } }) // deep-diff path
|
|
381
402
|
```
|
|
382
403
|
|
|
383
404
|
### setDiff(path?, value)
|
|
384
405
|
|
|
385
|
-
|
|
406
|
+
`setDiff` has two branches in compat:
|
|
407
|
+
- `setDiff(value)` calls base `Signal.set(value)` on current signal (deep-diff semantics).
|
|
408
|
+
- `setDiff(path, value)` delegates to compat `set(path, value)`.
|
|
386
409
|
|
|
387
410
|
```js
|
|
388
|
-
$.users.user1.setDiff({ profile: { name: '
|
|
411
|
+
await $.users.user1.setDiff({ profile: { name: 'Kate' } })
|
|
412
|
+
await $.users.user1.setDiff('profile', { name: 'Bob' }) // compat set semantics
|
|
389
413
|
```
|
|
390
414
|
|
|
391
415
|
### setEach(path?, object)
|
|
392
416
|
|
|
393
|
-
|
|
417
|
+
Racer-like per-key set. `setEach` iterates keys and applies compat `set` for each key.
|
|
418
|
+
- `setEach({ k: null })` stores `null`.
|
|
419
|
+
- `setEach({ k: undefined })` applies current delete semantics.
|
|
420
|
+
|
|
421
|
+
```js
|
|
422
|
+
await $.users.user1.setEach({ name: 'Bob', age: null })
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Null / Undefined Matrix (Compat)
|
|
426
|
+
|
|
427
|
+
| Call | Result |
|
|
428
|
+
| --- | --- |
|
|
429
|
+
| `set(path, null)` | stores `null` at `path` |
|
|
430
|
+
| `set(path, undefined)` | applies delete semantics at `path` |
|
|
431
|
+
| `setEach({ k: null })` | stores `null` for `k` |
|
|
432
|
+
| `setEach({ k: undefined })` | applies delete semantics for `k` |
|
|
394
433
|
|
|
395
434
|
```js
|
|
396
|
-
$.users.user1.
|
|
435
|
+
await $.users.user1.set('status', null) // status === null
|
|
436
|
+
await $.users.user1.setEach({ status: undefined }) // status deleted
|
|
397
437
|
```
|
|
398
438
|
|
|
399
439
|
### assign(object)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teamplay",
|
|
3
|
-
"version": "0.4.0-alpha.
|
|
3
|
+
"version": "0.4.0-alpha.27",
|
|
4
4
|
"description": "Full-stack signals ORM with multiplayer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
]
|
|
82
82
|
},
|
|
83
83
|
"license": "MIT",
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "f7a6412190f8b2ec9322331ad2dab7b8ac452f53"
|
|
85
85
|
}
|
package/utils/setDiffDeep.js
CHANGED
|
@@ -4,6 +4,12 @@ function isReactLike (value) {
|
|
|
4
4
|
return !!(value && typeof value === 'object' && typeof value.$$typeof === 'symbol')
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
function canDeepMutateObject (existing, updated) {
|
|
8
|
+
if (!isPlainObject(existing) || !isPlainObject(updated)) return false
|
|
9
|
+
if (isReactLike(existing) || isReactLike(updated)) return false
|
|
10
|
+
return true
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
export default function setDiffDeep (existing, updated) {
|
|
8
14
|
// Handle primitive types, null, and type mismatches
|
|
9
15
|
if (existing === null || updated === null ||
|
|
@@ -16,30 +22,37 @@ export default function setDiffDeep (existing, updated) {
|
|
|
16
22
|
// so we just return the original reference
|
|
17
23
|
if (existing === updated) return existing
|
|
18
24
|
|
|
25
|
+
if (isReactLike(existing) || isReactLike(updated)) return updated
|
|
26
|
+
|
|
19
27
|
// Handle arrays
|
|
20
28
|
if (Array.isArray(updated)) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
try {
|
|
30
|
+
if (!Reflect.set(existing, 'length', updated.length)) return updated
|
|
31
|
+
for (let i = 0; i < updated.length; i++) {
|
|
32
|
+
const nextValue = setDiffDeep(existing[i], updated[i])
|
|
33
|
+
if (!Reflect.set(existing, i, nextValue)) return updated
|
|
34
|
+
}
|
|
35
|
+
return existing
|
|
36
|
+
} catch {
|
|
37
|
+
return updated
|
|
24
38
|
}
|
|
25
|
-
return existing
|
|
26
39
|
}
|
|
27
40
|
|
|
28
|
-
// React elements are plain objects but must be treated as non-plain
|
|
29
|
-
if (isReactLike(updated)) return updated
|
|
30
|
-
|
|
31
41
|
// Handle non-plain objects - just return them as-is to fully overwrite
|
|
32
42
|
// and don't try to update an old object in-place
|
|
33
|
-
if (!
|
|
43
|
+
if (!canDeepMutateObject(existing, updated)) return updated
|
|
34
44
|
|
|
35
45
|
// Handle objects
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
try {
|
|
47
|
+
for (const key of Object.keys(existing)) {
|
|
48
|
+
if (!(key in updated) && !Reflect.deleteProperty(existing, key)) return updated
|
|
39
49
|
}
|
|
50
|
+
for (const key of Object.keys(updated)) {
|
|
51
|
+
const nextValue = setDiffDeep(existing[key], updated[key])
|
|
52
|
+
if (!Reflect.set(existing, key, nextValue)) return updated
|
|
53
|
+
}
|
|
54
|
+
return existing
|
|
55
|
+
} catch {
|
|
56
|
+
return updated
|
|
40
57
|
}
|
|
41
|
-
for (const key in updated) {
|
|
42
|
-
existing[key] = setDiffDeep(existing[key], updated[key])
|
|
43
|
-
}
|
|
44
|
-
return existing
|
|
45
58
|
}
|