Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: configurable produce implementation #3074

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
49f808a
allow `produce` to be swapped out in createReducer/createSlice
phryneas Jan 11, 2023
f0228f9
Make more Immer utils configurable
markerikson Feb 21, 2023
fb9d324
add buildable createDraftSafeSelector
Apr 4, 2023
293a9b9
make configurable createEntityAdapter
Apr 4, 2023
83a8931
unused type
Apr 4, 2023
411568a
declare immutable helper types once
Apr 4, 2023
d9e1341
build createDraftSafeSelector outside of createSelectorsFactory
Apr 4, 2023
e5f48f1
allow replacing RTKQ's usage of immer
Apr 5, 2023
4f6c897
use immutablehelpers for RTKQ's createSlice
Apr 5, 2023
28a87c9
named export instead of default
Apr 5, 2023
180d198
use specific freeze function instead of abusing createNextState
Apr 5, 2023
5bd963c
export buildCreateEntityAdapter
Apr 5, 2023
bc924e7
Merge branch 'v2.0-integration' into more-produce
Apr 5, 2023
9f9dfff
export ImmutableHelpers
Apr 5, 2023
a36f092
Merge branch 'v2.0-integration' into pr/configure-produce-implementation
Apr 5, 2023
27bcf3b
Merge branch 'pr/configure-produce-implementation' into more-produce
Apr 5, 2023
19d5b8d
create a defineImmutableHelpers identity function, and use for immer
Apr 5, 2023
9614298
don't use @internal import
Apr 5, 2023
7eb1fa0
import ImmutableHelpers type from RTK
Apr 5, 2023
115b856
fix entity adapter options not being optional
Apr 18, 2023
bfa1419
hope the PR gets happier
May 5, 2023
9d8f344
be extra assertive about nicking reselect's types
May 5, 2023
df861fd
Merge pull request #3327 from EskiMojo14/more-produce
markerikson May 5, 2023
080974d
Merge branch 'v2.0-integration' into pr/configure-produce-implementation
May 16, 2023
30b1b49
Merge branch 'v2.0-integration' into pr/configure-produce-implementation
EskiMojo14 May 29, 2023
7276087
Merge branch 'v2.0-integration' into pr/configure-produce-implementation
Oct 2, 2023
b43f501
rtkImports
Oct 2, 2023
0888fde
add missing createEntityAdapter overload
Oct 2, 2023
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
Prev Previous commit
Next Next commit
allow replacing RTKQ's usage of immer
  • Loading branch information
ben.durrant committed Apr 5, 2023
commit e5f48f116283dc6305b75ddf6ec5f5a39f90df27
12 changes: 8 additions & 4 deletions packages/toolkit/src/query/core/buildMiddleware/batchActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import type {
QuerySubstateIdentifier,
Subscribers,
} from '../apiState'
import { produceWithPatches } from 'immer'
import type { AnyAction } from '@reduxjs/toolkit';
import type { AnyAction } from '@reduxjs/toolkit'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'

// Copied from https://github.com/feross/queue-microtask
Expand All @@ -30,7 +29,12 @@ const queueMicrotaskShim =

export const buildBatchedActionsHandler: InternalHandlerBuilder<
[actionShouldContinue: boolean, subscriptionExists: boolean]
> = ({ api, queryThunk, internalState }) => {
> = ({
api,
queryThunk,
internalState,
immutableHelpers: { createWithPatches },
}) => {
const subscriptionsPrefix = `${api.reducerPath}/subscriptions`

let previousSubscriptions: SubscriptionState =
Expand Down Expand Up @@ -125,7 +129,7 @@ export const buildBatchedActionsHandler: InternalHandlerBuilder<
JSON.stringify(internalState.currentSubscriptions)
)
// Figure out a smaller diff between original and current
const [, patches] = produceWithPatches(
const [, patches] = createWithPatches(
previousSubscriptions,
() => newSubscriptions
)
Expand Down
3 changes: 2 additions & 1 deletion packages/toolkit/src/query/core/buildMiddleware/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { buildInvalidationByTagsHandler } from './invalidationByTags'
import { buildPollingHandler } from './polling'
import type {
BuildMiddlewareInput,
BuildSubMiddlewareInput,
InternalHandlerBuilder,
InternalMiddlewareState,
} from './types'
Expand Down Expand Up @@ -63,7 +64,7 @@ export function buildMiddleware<
currentSubscriptions: {},
}

const builderArgs = {
const builderArgs: BuildSubMiddlewareInput = {
...(input as any as BuildMiddlewareInput<
EndpointDefinitions,
string,
Expand Down
2 changes: 2 additions & 0 deletions packages/toolkit/src/query/core/buildMiddleware/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {
QueryThunkArg,
ThunkResult,
} from '../buildThunks'
import type { ImmutableHelpers } from '../../tsHelpers'

export type QueryStateMeta<T> = Record<string, undefined | T>
export type TimeoutId = ReturnType<typeof setTimeout>
Expand All @@ -43,6 +44,7 @@ export interface BuildMiddlewareInput<
mutationThunk: MutationThunk
api: Api<any, Definitions, ReducerPath, TagTypes>
assertTagType: AssertTagTypes
immutableHelpers: Pick<ImmutableHelpers, 'createWithPatches'>
}

export type SubMiddlewareApi = MiddlewareAPI<
Expand Down
4 changes: 3 additions & 1 deletion packages/toolkit/src/query/core/buildSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import type {
QueryDefinition,
} from '../endpointDefinitions'
import type { Patch } from 'immer'
import { applyPatches } from 'immer'
import { onFocus, onFocusLost, onOffline, onOnline } from './setupListeners'
import {
isDocumentVisible,
Expand All @@ -41,6 +40,7 @@ import {
} from '../utils'
import type { ApiContext } from '../apiTypes'
import { isUpsertQuery } from './buildInitiate'
import type { ImmutableHelpers } from '../tsHelpers'

function updateQuerySubstateIfExists(
state: QueryState<any>,
Expand Down Expand Up @@ -99,6 +99,7 @@ export function buildSlice({
},
assertTagType,
config,
immutableHelpers: { applyPatches },
}: {
reducerPath: string
queryThunk: QueryThunk
Expand All @@ -109,6 +110,7 @@ export function buildSlice({
ConfigState<string>,
'online' | 'focused' | 'middlewareRegistered'
>
immutableHelpers: Pick<ImmutableHelpers, 'applyPatches'>
}) {
const resetApiState = createAction(`${reducerPath}/resetApiState`)
const querySlice = createSlice({
Expand Down
7 changes: 4 additions & 3 deletions packages/toolkit/src/query/core/buildThunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
isRejectedWithValue,
} from '@reduxjs/toolkit'
import type { Patch } from 'immer'
import { isDraftable, produceWithPatches } from 'immer'
import type {
AnyAction,
ThunkAction,
Expand All @@ -44,7 +43,7 @@ import { createAsyncThunk, SHOULD_AUTOBATCH } from '@reduxjs/toolkit'
import { HandledError } from '../HandledError'

import type { ApiEndpointQuery, PrefetchOptions } from './module'
import type { UnwrapPromise } from '../tsHelpers'
import type { ImmutableHelpers, UnwrapPromise } from '../tsHelpers'

declare module './module' {
export interface ApiEndpointQuery<
Expand Down Expand Up @@ -222,12 +221,14 @@ export function buildThunks<
context: { endpointDefinitions },
serializeQueryArgs,
api,
immutableHelpers: { isDraftable, createWithPatches },
}: {
baseQuery: BaseQuery
reducerPath: ReducerPath
context: ApiContext<Definitions>
serializeQueryArgs: InternalSerializeQueryArgs
api: Api<BaseQuery, Definitions, ReducerPath, any>
immutableHelpers: Pick<ImmutableHelpers, 'isDraftable' | 'createWithPatches'>
}) {
type State = RootState<any, string, ReducerPath>

Expand Down Expand Up @@ -264,7 +265,7 @@ export function buildThunks<
}
if ('data' in currentState) {
if (isDraftable(currentState.data)) {
const [, patches, inversePatches] = produceWithPatches(
const [, patches, inversePatches] = createWithPatches(
currentState.data,
updateRecipe
)
Expand Down
29 changes: 26 additions & 3 deletions packages/toolkit/src/query/core/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import type {
QueryActionCreatorResult,
} from './buildInitiate'
import { buildInitiate } from './buildInitiate'
import type { ImmutableHelpers } from '../tsHelpers'
import { assertCast, safeAssign } from '../tsHelpers'
import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs'
import type { SliceActions } from './buildSlice'
Expand All @@ -48,7 +49,12 @@ import type { BaseQueryFn } from '../baseQueryTypes'
import type { ReferenceCacheLifecycle } from './buildMiddleware/cacheLifecycle'
import type { ReferenceQueryLifecycle } from './buildMiddleware/queryLifecycle'
import type { ReferenceCacheCollection } from './buildMiddleware/cacheCollection'
import { enablePatches } from 'immer'
import {
applyPatches,
enablePatches,
isDraftable,
produceWithPatches,
} from 'immer'

/**
* `ifOlderThan` - (default: `false` | `number`) - _number is value in seconds_
Expand All @@ -71,7 +77,8 @@ export type CoreModule =
| ReferenceQueryLifecycle
| ReferenceCacheCollection

export interface ThunkWithReturnValue<T> extends ThunkAction<T, any, any, AnyAction> {}
export interface ThunkWithReturnValue<T>
extends ThunkAction<T, any, any, AnyAction> {}

declare module '../apiTypes' {
export interface ApiModules<
Expand Down Expand Up @@ -450,6 +457,13 @@ export type ListenerActions = {

export type InternalActions = SliceActions & ListenerActions

interface CoreModuleOptions {
immutableHelpers?: Pick<
ImmutableHelpers,
'createWithPatches' | 'applyPatches' | 'isDraftable'
>
}

/**
* Creates a module containing the basic redux logic for use with `buildCreateApi`.
*
Expand All @@ -458,7 +472,13 @@ export type InternalActions = SliceActions & ListenerActions
* const createBaseApi = buildCreateApi(coreModule());
* ```
*/
export const coreModule = (): Module<CoreModule> => ({
export const coreModule = ({
immutableHelpers = {
createWithPatches: produceWithPatches,
applyPatches,
isDraftable,
},
}: CoreModuleOptions = {}): Module<CoreModule> => ({
name: coreModuleName,
init(
api,
Expand Down Expand Up @@ -518,6 +538,7 @@ export const coreModule = (): Module<CoreModule> => ({
context,
api,
serializeQueryArgs,
immutableHelpers,
})

const { reducer, actions: sliceActions } = buildSlice({
Expand All @@ -533,6 +554,7 @@ export const coreModule = (): Module<CoreModule> => ({
keepUnusedDataFor,
reducerPath,
},
immutableHelpers,
})

safeAssign(api.util, {
Expand All @@ -551,6 +573,7 @@ export const coreModule = (): Module<CoreModule> => ({
mutationThunk,
api,
assertTagType,
immutableHelpers,
})
safeAssign(api.util, middlewareActions)

Expand Down
19 changes: 19 additions & 0 deletions packages/toolkit/src/query/tsHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
import type { Draft, Patch, applyPatches } from 'immer'

export interface ImmutableHelpers {
createNextState: <Base>(
base: Base,
recipe: (draft: Draft<Base>) => void | Base | Draft<Base>
) => Base
createWithPatches: <Base>(
base: Base,
recipe: (draft: Draft<Base>) => void | Base | Draft<Base>
) => readonly [Base, Patch[], Patch[]]
// depends on an Objectish type that immer doesn't export
applyPatches: typeof applyPatches
isDraft(value: any): boolean
isDraftable(value: any): boolean
original<T>(value: T): T | undefined
current<T>(value: T): T
}

export type Id<T> = { [K in keyof T]: T[K] } & {}
export type WithRequiredProp<T, K extends keyof T> = Omit<T, K> &
Required<Pick<T, K>>
Expand Down
8 changes: 7 additions & 1 deletion packages/toolkit/src/tsHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import type { Middleware, StoreEnhancer } from 'redux'
import type { Draft, Patch, applyPatches } from 'immer'
import type { MiddlewareArray } from './utils'
import type { Draft } from 'immer'

export interface ImmutableHelpers {
createNextState: <Base>(
base: Base,
recipe: (draft: Draft<Base>) => void | Base | Draft<Base>
) => Base
createWithPatches: <Base>(
base: Base,
recipe: (draft: Draft<Base>) => void | Base | Draft<Base>
) => readonly [Base, Patch[], Patch[]]
// depends on an Objectish type that immer doesn't export
applyPatches: typeof applyPatches
isDraft(value: any): boolean
isDraftable(value: any): boolean
original<T>(value: T): T | undefined
Expand Down