Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions packages/toolkit/src/createDraftSafeSelector.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
import { current, isDraft } from 'immer'
import { createSelector } from 'reselect'
import type { ImmutableHelpers } from './tsHelpers'
import { immutableHelpers } from './immer'

export type BuildCreateDraftSafeSelectorConfiguration = Pick<
ImmutableHelpers,
'isDraft' | 'current'
>

export function buildCreateDraftSafeSelector({
isDraft,
current,
}: BuildCreateDraftSafeSelectorConfiguration): typeof createSelector {
return function createDraftSafeSelector(...args: unknown[]) {
const selector = (createSelector as any)(...args)
const wrappedSelector = (value: unknown, ...rest: unknown[]) =>
selector(isDraft(value) ? current(value) : value, ...rest)
return wrappedSelector as any
}
}

/**
* "Draft-Safe" version of `reselect`'s `createSelector`:
Expand All @@ -8,11 +26,5 @@ import { createSelector } from 'reselect'
* that might be possibly outdated if the draft has been modified since.
* @public
*/
export const createDraftSafeSelector: typeof createSelector = (
...args: unknown[]
) => {
const selector = (createSelector as any)(...args)
const wrappedSelector = (value: unknown, ...rest: unknown[]) =>
selector(isDraft(value) ? current(value) : value, ...rest)
return wrappedSelector as any
}
export const createDraftSafeSelector: typeof createSelector =
buildCreateDraftSafeSelector(immutableHelpers)
33 changes: 10 additions & 23 deletions packages/toolkit/src/createReducer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import type { Draft } from 'immer'
import { produce as createNextState, isDraft, isDraftable } from 'immer'
import type { AnyAction, Action, Reducer } from 'redux'
import type { ActionReducerMapBuilder } from './mapBuilders'
import { executeReducerBuilderCallback } from './mapBuilders'
import type { NoInfer } from './tsHelpers'
import { makeFreezeDraftable } from './utils'
import type { ImmutableHelpers, NoInfer } from './tsHelpers'
import { immutableHelpers } from './immer'

/**
* Defines a mapping from action types to corresponding action object shapes.
Expand Down Expand Up @@ -153,25 +152,17 @@ const reducer = createReducer(
): ReducerWithInitialState<S>
}

export interface BuildCreateReducerConfiguration {
createNextState: <Base>(
base: Base,
recipe: (draft: Draft<Base>) => void | Base | Draft<Base>
) => Base
isDraft(value: any): boolean
isDraftable(value: any): boolean
}
export type BuildCreateReducerConfiguration = Pick<
ImmutableHelpers,
'createNextState' | 'isDraft' | 'isDraftable' | 'freeze'
>

export function buildCreateReducer({
createNextState,
isDraft,
isDraftable,
freeze,
}: BuildCreateReducerConfiguration): CreateReducer {
const freezeDraftable = makeFreezeDraftable({
createNextState,
isDraft,
isDraftable,
})
return function createReducer<S extends NotFunction<any>>(
initialState: S | (() => S),
mapOrBuilderCallback: (builder: ActionReducerMapBuilder<S>) => void
Expand All @@ -190,9 +181,9 @@ export function buildCreateReducer({
// Ensure the initial state gets frozen either way (if draftable)
let getInitialState: () => S
if (isStateFunction(initialState)) {
getInitialState = () => freezeDraftable(initialState())
getInitialState = () => freeze(initialState(), true)
} else {
const frozenInitialState = freezeDraftable(initialState)
const frozenInitialState = freeze(initialState, true)
getInitialState = () => frozenInitialState
}

Expand Down Expand Up @@ -256,8 +247,4 @@ export function buildCreateReducer({
}
}

export const createReducer = buildCreateReducer({
createNextState,
isDraft,
isDraftable,
})
export const createReducer = buildCreateReducer(immutableHelpers)
13 changes: 4 additions & 9 deletions packages/toolkit/src/createSlice.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Reducer } from 'redux'
import { produce as createNextState, isDraft, isDraftable } from 'immer'
import type {
ActionCreatorWithoutPayload,
PayloadAction,
Expand All @@ -18,7 +17,7 @@ import { buildCreateReducer } from './createReducer'
import type { ActionReducerMapBuilder } from './mapBuilders'
import { executeReducerBuilderCallback } from './mapBuilders'
import type { NoInfer } from './tsHelpers'
import { makeFreezeDraftable } from './utils'
import { immutableHelpers } from './immer'

let hasWarnedAboutObjectNotation = false

Expand Down Expand Up @@ -283,7 +282,7 @@ export function buildCreateSlice(
configuration: BuildCreateSliceConfiguration
): CreateSlice {
const createReducer = buildCreateReducer(configuration)
const freezeDraftable = makeFreezeDraftable(configuration)
const { freeze } = configuration

return function createSlice<
State,
Expand Down Expand Up @@ -311,7 +310,7 @@ export function buildCreateSlice(
const initialState =
typeof options.initialState == 'function'
? options.initialState
: freezeDraftable(options.initialState)
: freeze(options.initialState)

const reducers = options.reducers || {}

Expand Down Expand Up @@ -394,8 +393,4 @@ export function buildCreateSlice(
}
}

export const createSlice = buildCreateSlice({
createNextState,
isDraft,
isDraftable,
})
export const createSlice = buildCreateSlice(immutableHelpers)
75 changes: 46 additions & 29 deletions packages/toolkit/src/entities/create_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,56 @@ import type {
EntityAdapter,
} from './models'
import { createInitialStateFactory } from './entity_state'
import { createSelectorsFactory } from './state_selectors'
import { createSortedStateAdapter } from './sorted_state_adapter'
import { createUnsortedStateAdapter } from './unsorted_state_adapter'
import { buildCreateSelectorsFactory } from './state_selectors'
import { buildCreateSortedStateAdapter } from './sorted_state_adapter'
import { buildCreateUnsortedStateAdapter } from './unsorted_state_adapter'
import type { BuildCreateDraftSafeSelectorConfiguration } from '..'
import type { BuildStateOperatorConfiguration } from './state_adapter'
import { immutableHelpers } from '../immer'

/**
*
* @param options
*
* @public
*/
export function createEntityAdapter<T>(
options: {
export interface BuildCreateEntityAdapterConfiguration
extends BuildCreateDraftSafeSelectorConfiguration,
BuildStateOperatorConfiguration {}

export type CreateEntityAdapter = {
<T>(options?: {
selectId?: IdSelector<T>
sortComparer?: false | Comparer<T>
} = {}
): EntityAdapter<T> {
const { selectId, sortComparer }: EntityDefinition<T> = {
sortComparer: false,
selectId: (instance: any) => instance.id,
...options,
}
}): EntityAdapter<T>
}

const stateFactory = createInitialStateFactory<T>()
const selectorsFactory = createSelectorsFactory<T>()
const stateAdapter = sortComparer
? createSortedStateAdapter(selectId, sortComparer)
: createUnsortedStateAdapter(selectId)
export function buildCreateEntityAdapter(
config: BuildCreateEntityAdapterConfiguration
): CreateEntityAdapter {
const createSelectorsFactory = buildCreateSelectorsFactory(config)
const createUnsortedStateAdapter = buildCreateUnsortedStateAdapter(config)
const createSortedStateAdapter = buildCreateSortedStateAdapter(config)
return function createEntityAdapter<T>(
options: {
selectId?: IdSelector<T>
sortComparer?: false | Comparer<T>
} = {}
): EntityAdapter<T> {
const { selectId, sortComparer }: EntityDefinition<T> = {
sortComparer: false,
selectId: (instance: any) => instance.id,
...options,
}

return {
selectId,
sortComparer,
...stateFactory,
...selectorsFactory,
...stateAdapter,
const stateFactory = createInitialStateFactory<T>()
const selectorsFactory = createSelectorsFactory<T>()
const stateAdapter = sortComparer
? createSortedStateAdapter(selectId, sortComparer)
: createUnsortedStateAdapter(selectId)

return {
selectId,
sortComparer,
...stateFactory,
...selectorsFactory,
...stateAdapter,
}
}
}

export const createEntityAdapter = buildCreateEntityAdapter(immutableHelpers)
Loading