Browse Source

Map-aware.

Herby Vojčík 5 years ago
parent
commit
f6f553b449
2 changed files with 45 additions and 5 deletions
  1. 15 0
      README.md
  2. 30 5
      src/cow-value-model.js

+ 15 - 0
README.md

@@ -138,6 +138,7 @@ to get specified key from any object.
 Specify keys by passing a list of keys to `deepGetOrNil`.
 Key can be either:
  - number
+ - `keyInMap(obj)`
  - array of Keys
  - anything else, which is `toString()`ed and dot-split.
 
@@ -178,6 +179,9 @@ city({address: {city: null}});
 If you put a number in a list of keys to use,
 an object will be treated as an array.
 
+If you put a `keyInMap(obj)` in a list of keys to use,
+an object will be treated as a `Map`.
+
 That way you can create eg. `const c = deget("person", 34, "name")`
 to access `obj.person[34].name` with `c(obj)`.
 
@@ -195,6 +199,7 @@ are not present, they are created.
 Specify keys by passing a list of keys to `deepCopyOnWrite`.
 Key can be either:
  - number
+ - `keyInMap(obj)`
  - array of Keys
  - anything else, which is `toString()`ed and dot-split.
 
@@ -251,6 +256,16 @@ using `[...obj]`, not using `{...obj}`.
 That way you can create eg. `const c = decow("person", 34, "name")`
 to "set" `obj.person[34].name` with `c(val)(obj)`.
 
+If you put a `keyInMap(key)` in a list of keys to use,
+an object will be treated as a `Map` (unlike the default string case,
+where it is treated as an object), so copy wil be created
+using `new Map(obj)`, not using `{...obj}`.
+
+### `keyInMap(obj)`
+### `kim(obj)`
+
+Creates "`obj` as an index in a map".
+
 ### `cowValueModel(key, ...)`
 
 Deprecated.

+ 30 - 5
src/cow-value-model.js

@@ -1,15 +1,38 @@
-function copyWith (obj, key, value) {
-    const result = typeof key === 'number' ? obj == null ? [] : [...obj] : obj == null ? {} : {...obj};
+function copyArrayWith (obj, key, value) {
+    const result = obj == null ? [] : [...obj];
     result[key] = value;
     return result;
 }
 
+function copyMapWith (obj, key, value) {
+    const result = obj == null ? new Map() : new Map(obj);
+    result.set(key, value);
+    return result;
+}
+
+function copyObjectWith (obj, key, value) {
+    const result = obj == null ? {} : {...obj};
+    result[key] = value;
+    return result;
+}
+
+const isMapKey = key => typeof key === 'object' && key.isKeyInMap === true;
+
+export const keyInMap = key => ({isKeyInMap: true, key});
+
+export const kim = keyInMap;
+
+const copyWith = (obj, key, value) =>
+    typeof key === 'number' ? copyArrayWith(obj, key, value) :
+        isMapKey(key) ? copyMapWith(obj, key.key, value) :
+            copyObjectWith(obj, key, value);
+
 const constructKeys = function (keyDescriptions) {
     const keys = [];
 
     function fillKeys (keyDescriptions) {
         keyDescriptions.forEach(each => {
-            if (typeof each === 'number') keys.push(each);
+            if (typeof each === 'number' || isMapKey(each)) keys.push(each);
             else if (Array.isArray(each)) fillKeys(each);
             else keys.push(...each.toString().split('.'));
         });
@@ -20,13 +43,15 @@ const constructKeys = function (keyDescriptions) {
     return keys;
 };
 
-const deepGet = (keys, obj) => keys.reduce((x, key) => x == null ? undefined : x[key], obj);
+const getKey = (x, key) => x == null ? undefined : isMapKey(key) ? x.get(key.key) : x[key];
+
+const deepGet = (keys, obj) => keys.reduce(getKey, obj);
 
 const deepPut = (keys, obj, val) => {
     function setVal (x, index) {
         if (index >= keys.length) return val;
         const key = keys[index],
-            value = x == null ? undefined : x[key],
+            value = getKey(x, key),
             modified = setVal(value, index + 1);
         return value === modified ? x : copyWith(x, key, modified);
     }