Skip to content

Commit 2ad4bb4

Browse files
committed
Update to new version of upsert proposal
1 parent 4d92026 commit 2ad4bb4

File tree

4 files changed

+53
-94
lines changed

4 files changed

+53
-94
lines changed

packages/toolkit/src/combineSlices.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type {
88
UnionToIntersection,
99
WithOptionalProp,
1010
} from './tsHelpers'
11-
import { emplace } from './utils'
11+
import { getOrInsertComputed } from './utils'
1212

1313
type SliceLike<ReducerPath extends string, State> = {
1414
reducerPath: ReducerPath
@@ -324,8 +324,10 @@ const createStateProxy = <State extends object>(
324324
state: State,
325325
reducerMap: Partial<Record<string, Reducer>>,
326326
) =>
327-
emplace(stateProxyMap, state, {
328-
insert: () =>
327+
getOrInsertComputed(
328+
stateProxyMap,
329+
state,
330+
() =>
329331
new Proxy(state, {
330332
get: (target, prop, receiver) => {
331333
if (prop === ORIGINAL_STATE) return target
@@ -350,7 +352,7 @@ const createStateProxy = <State extends object>(
350352
return result
351353
},
352354
}),
353-
}) as State
355+
) as State
354356

355357
const original = (state: any) => {
356358
if (!isStateProxy(state)) {

packages/toolkit/src/createSlice.ts

+20-20
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { createReducer } from './createReducer'
2626
import type { ActionReducerMapBuilder, TypedActionCreator } from './mapBuilders'
2727
import { executeReducerBuilderCallback } from './mapBuilders'
2828
import type { Id, TypeGuard } from './tsHelpers'
29-
import { emplace } from './utils'
29+
import { getOrInsertComputed } from './utils'
3030

3131
const asyncThunkSymbol = /* @__PURE__ */ Symbol.for(
3232
'rtk-slice-createasyncthunk',
@@ -769,25 +769,25 @@ export function buildCreateSlice({ creators }: BuildCreateSliceConfig = {}) {
769769
function getSelectors(
770770
selectState: (rootState: any) => State = selectSelf,
771771
) {
772-
const selectorCache = emplace(injectedSelectorCache, injected, {
773-
insert: () => new WeakMap(),
774-
})
775-
776-
return emplace(selectorCache, selectState, {
777-
insert: () => {
778-
const map: Record<string, Selector<any, any>> = {}
779-
for (const [name, selector] of Object.entries(
780-
options.selectors ?? {},
781-
)) {
782-
map[name] = wrapSelector(
783-
selector,
784-
selectState,
785-
getInitialState,
786-
injected,
787-
)
788-
}
789-
return map
790-
},
772+
const selectorCache = getOrInsertComputed(
773+
injectedSelectorCache,
774+
injected,
775+
() => new WeakMap(),
776+
)
777+
778+
return getOrInsertComputed(selectorCache, selectState, () => {
779+
const map: Record<string, Selector<any, any>> = {}
780+
for (const [name, selector] of Object.entries(
781+
options.selectors ?? {},
782+
)) {
783+
map[name] = wrapSelector(
784+
selector,
785+
selectState,
786+
getInitialState,
787+
injected,
788+
)
789+
}
790+
return map
791791
}) as any
792792
}
793793
return {

packages/toolkit/src/dynamicMiddleware/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { compose } from 'redux'
33
import { createAction } from '../createAction'
44
import { isAllOf } from '../matchers'
55
import { nanoid } from '../nanoid'
6-
import { emplace, find } from '../utils'
6+
import { find, getOrInsertComputed } from '../utils'
77
import type {
88
AddMiddleware,
99
DynamicMiddleware,
@@ -73,7 +73,7 @@ export const createDynamicMiddleware = <
7373

7474
const getFinalMiddleware: Middleware<{}, State, DispatchType> = (api) => {
7575
const appliedMiddleware = Array.from(middlewareMap.values()).map((entry) =>
76-
emplace(entry.applied, api, { insert: () => entry.middleware(api) }),
76+
getOrInsertComputed(entry.applied, api, entry.middleware),
7777
)
7878
return compose(...appliedMiddleware)
7979
}

packages/toolkit/src/utils.ts

+25-68
Original file line numberDiff line numberDiff line change
@@ -87,81 +87,38 @@ export function freezeDraftable<T>(val: T) {
8787
return isDraftable(val) ? createNextState(val, () => {}) : val
8888
}
8989

90-
interface WeakMapEmplaceHandler<K extends object, V> {
91-
/**
92-
* Will be called to get value, if no value is currently in map.
93-
*/
94-
insert?(key: K, map: WeakMap<K, V>): V
95-
/**
96-
* Will be called to update a value, if one exists already.
97-
*/
98-
update?(previous: V, key: K, map: WeakMap<K, V>): V
99-
}
90+
export function getOrInsert<K extends object, V>(
91+
map: WeakMap<K, V>,
92+
key: K,
93+
value: V,
94+
): V
95+
export function getOrInsert<K, V>(map: Map<K, V>, key: K, value: V): V
96+
export function getOrInsert<K extends object, V>(
97+
map: Map<K, V> | WeakMap<K, V>,
98+
key: K,
99+
value: V,
100+
): V {
101+
if (map.has(key)) return map.get(key) as V
100102

101-
interface MapEmplaceHandler<K, V> {
102-
/**
103-
* Will be called to get value, if no value is currently in map.
104-
*/
105-
insert?(key: K, map: Map<K, V>): V
106-
/**
107-
* Will be called to update a value, if one exists already.
108-
*/
109-
update?(previous: V, key: K, map: Map<K, V>): V
103+
return map.set(key, value).get(key) as V
110104
}
111105

112-
export function emplace<K, V>(
113-
map: Map<K, V>,
106+
export function getOrInsertComputed<K extends object, V>(
107+
map: WeakMap<K, V>,
114108
key: K,
115-
handler: MapEmplaceHandler<K, V>,
109+
compute: (key: K) => V,
116110
): V
117-
export function emplace<K extends object, V>(
118-
map: WeakMap<K, V>,
111+
export function getOrInsertComputed<K, V>(
112+
map: Map<K, V>,
119113
key: K,
120-
handler: WeakMapEmplaceHandler<K, V>,
114+
compute: (key: K) => V,
121115
): V
122-
/**
123-
* Allow inserting a new value, or updating an existing one
124-
* @throws if called for a key with no current value and no `insert` handler is provided
125-
* @returns current value in map (after insertion/updating)
126-
* ```ts
127-
* // return current value if already in map, otherwise initialise to 0 and return that
128-
* const num = emplace(map, key, {
129-
* insert: () => 0
130-
* })
131-
*
132-
* // increase current value by one if already in map, otherwise initialise to 0
133-
* const num = emplace(map, key, {
134-
* update: (n) => n + 1,
135-
* insert: () => 0,
136-
* })
137-
*
138-
* // only update if value's already in the map - and increase it by one
139-
* if (map.has(key)) {
140-
* const num = emplace(map, key, {
141-
* update: (n) => n + 1,
142-
* })
143-
* }
144-
* ```
145-
*
146-
* @remarks
147-
* Based on https://github.com/tc39/proposal-upsert currently in Stage 2 - maybe in a few years we'll be able to replace this with direct method calls
148-
*/
149-
export function emplace<K extends object, V>(
150-
map: WeakMap<K, V>,
116+
export function getOrInsertComputed<K extends object, V>(
117+
map: Map<K, V> | WeakMap<K, V>,
151118
key: K,
152-
handler: WeakMapEmplaceHandler<K, V>,
119+
compute: (key: K) => V,
153120
): V {
154-
if (map.has(key)) {
155-
let value = map.get(key) as V
156-
if (handler.update) {
157-
value = handler.update(value, key, map)
158-
map.set(key, value)
159-
}
160-
return value
161-
}
162-
if (!handler.insert)
163-
throw new Error('No insert provided for key not already in map')
164-
const inserted = handler.insert(key, map)
165-
map.set(key, inserted)
166-
return inserted
121+
if (map.has(key)) return map.get(key) as V
122+
123+
return map.set(key, compute(key)).get(key) as V
167124
}

0 commit comments

Comments
 (0)