title: Upsert
stage: 2.7
contributors: Jonas Haukenes, Daniel Minor
markEffects: true
Introduction
Given a `key` and a value, the `getOrInsert` method will return the existing value if it exists, or otherwise
insert the provided default value and return that value.
Similarly, given a `key` and a callback function, the `getOrInsertComputed` method will return the existing value if it
exists, or otherwise insert the returned value of the callback function, and return that value.
Map.prototype.getOrInsert ( _key_, _value_ )
When the getOrInsert method is called the following steps are taken:
1. Let _M_ be the *this* value.
1. Perform ? RequireInternalSlot(_M_, [[MapData]]).
1. Set _key_ to CanonicalizeKeyedCollectionKey(_key_).
1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[MapData]], do
1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, return _p_.[[Value]].
1. Let _p_ be the Record { [[Key]]: _key_, [[Value]]: _value_ }.
1. Append _p_ to _M_.[[MapData]].
1. Return _value_.
Map.prototype.getOrInsertComputed ( _key_, _callback_ )
When the getOrInsertComputed method is called the following steps are taken:
1. Let _M_ be the *this* value.
1. Perform ? RequireInternalSlot(_M_, [[MapData]]).
1. If IsCallable(_callback_) is *false*, throw a *TypeError* exception.
1. Set _key_ to CanonicalizeKeyedCollectionKey(_key_).
1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[MapData]], do
1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, return _p_.[[Value]].
1. Let _value_ be ? Call(_callback_, *undefined*, « _key_ »).
1. NOTE: The Map may have been modified during execution of _callback_.
1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[MapData]], do
1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, then
1. Set _p_.[[Value]] to _value_.
1. Return _value_.
1. Let _p_ be the Record { [[Key]]: _key_, [[Value]]: _value_ }.
1. Append _p_ to _M_.[[MapData]].
1. Return _value_.
WeakMap.prototype.getOrInsert ( _key_, _value_ )
When the getOrInsert method is called the following steps are taken:
1. Let _M_ be the *this* value.
1. Perform ? RequireInternalSlot(_M_, [[WeakMapData]]).
1. If CanBeHeldWeakly(_key_) is *false*, throw a *TypeError* exception.
1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[WeakMapData]], do
1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, return _p_.[[Value]].
1. Let _p_ be the Record { [[Key]]: _key_, [[Value]]: _value_ }.
1. Append _p_ to _M_.[[WeakMapData]].
1. Return _value_.
WeakMap.prototype.getOrInsertComputed ( _key_, _callback_ )
When the getOrInsertComputed method is called the following steps are taken:
1. Let _M_ be the *this* value.
1. Perform ? RequireInternalSlot(_M_, [[WeakMapData]]).
1. If CanBeHeldWeakly(_key_) is *false*, throw a *TypeError* exception.
1. If IsCallable(_callback_) is *false*, throw a *TypeError* exception.
1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[WeakMapData]], do
1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, return _p_.[[Value]].
1. Let _value_ be ? Call(_callback_, *undefined*, « _key_ »).
1. NOTE: The WeakMap may have been modified during execution of _callback_.
1. For each Record { [[Key]], [[Value]] } _p_ of _M_.[[WeakMapData]], do
1. If _p_.[[Key]] is not ~empty~ and SameValue(_p_.[[Key]], _key_) is *true*, then
1. Set _p_.[[Value]] to _value_.
1. Return _value_.
1. Let _p_ be the Record { [[Key]]: _key_, [[Value]]: _value_ }.
1. Append _p_ to _M_.[[WeakMapData]].
1. Return _value_.