Skip to content

Commit

Permalink
Dont delete initial initialValues structure on withCleanUp (#3619)
Browse files Browse the repository at this point in the history
* Dont delete initialValues structure on withCleanUp

* Refactor the implementation of deleteInWithCleanUp

* Add new test for deleteInWithCleanUp

* Add new test for the blur reducer

* Attempt to fix flow error breaking build 🤞
  • Loading branch information
ms88privat authored and erikras committed Mar 23, 2018
1 parent 2c6b92e commit a97606f
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 35 deletions.
33 changes: 31 additions & 2 deletions src/__tests__/deleteInWithCleanUp.spec.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import createDeleteInWithCleanUp from '../deleteInWithCleanUp'
import createCreateDeleteInWithCleanUp from '../deleteInWithCleanUp'
import plain from '../structure/plain'
import plainExpectations from '../structure/plain/__tests__/expectations'
import immutable from '../structure/immutable'
import immutableExpectations from '../structure/immutable/__tests__/expectations'

const describeDeleteInWithCleanUp = (name, structure, setup) => {
const { fromJS } = structure
const deleteInWithCleanUp = createDeleteInWithCleanUp(structure)
const deleteInWithCleanUp = createCreateDeleteInWithCleanUp(structure)()

describe(name, () => {
beforeAll(() => {
Expand Down Expand Up @@ -145,6 +145,35 @@ const describeDeleteInWithCleanUp = (name, structure, setup) => {
)
).toEqualMap({})
})

it('should only delete cats because I am a dog person', () => {
const validation = (structure) => (state, path) => path.startsWith('cat')
const deleteInSpecial = createCreateDeleteInWithCleanUp(structure)(validation)

expect(
deleteInSpecial(
fromJS({
dog: 'Scooby',
cat: 'Garfield'
}),
'dog'
)
).toEqualMap({
dog: 'Scooby',
cat: 'Garfield'
})
expect(
deleteInSpecial(
fromJS({
dog: 'Scooby',
cat: 'Garfield'
}),
'cat'
)
).toEqualMap({
dog: 'Scooby',
})
})
})
}

Expand Down
36 changes: 36 additions & 0 deletions src/__tests__/helpers/reducer.blur.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,42 @@ const describeBlur = (reducer, expect, { fromJS, setIn }) => () => {
})
})

it('should NOT remove nested value container if it is included inside the initial values', () => {
const state = reducer(
fromJS({
foo: {
initial: {
nested: {}
},
values: {
nested: {
myField: 'initialValue'
}
}
}
}),
blur('foo', 'nested.myField', '', true)
)
expect(state).toEqualMap({
foo: {
anyTouched: true,
fields: {
nested: {
myField: {
touched: true
}
}
},
initial: {
nested: {}
},
values: {
nested: {}
}
}
})
})

it('should set nested value on blur', () => {
const state = reducer(
fromJS({
Expand Down
18 changes: 15 additions & 3 deletions src/createReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,22 @@ import {
CLEAR_FIELDS,
UPDATE_SYNC_WARNINGS
} from './actionTypes'
import createDeleteInWithCleanUp from './deleteInWithCleanUp'
import createCreateDeleteInWithCleanUp from './deleteInWithCleanUp'
import plain from './structure/plain'
import type { Action, Structure } from './types.js.flow'

const shouldDelete = ({ getIn }) => (state, path) => {
let initialValuesPath = null

if (path.startsWith('values')) {
initialValuesPath = path.replace('values', 'initial')
}

const initialValueComparison = initialValuesPath ? (getIn(state, initialValuesPath) === undefined) : true

return (getIn(state, path) !== undefined) && initialValueComparison
}

const isReduxFormAction = action =>
action &&
action.type &&
Expand All @@ -61,8 +73,8 @@ function createReducer<M, L>(structure: Structure<M, L>) {
some,
splice
} = structure
const deleteInWithCleanUp = createDeleteInWithCleanUp(structure)
const plainDeleteInWithCleanUp = createDeleteInWithCleanUp(plain)
const deleteInWithCleanUp = createCreateDeleteInWithCleanUp(structure)(shouldDelete)
const plainDeleteInWithCleanUp = createCreateDeleteInWithCleanUp(plain)(shouldDelete)
const doSplice = (state, key, field, index, removeNum, value, force) => {
const existing = getIn(state, `${key}.${field}`)
return existing || force
Expand Down
72 changes: 42 additions & 30 deletions src/deleteInWithCleanUp.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,53 @@
import { toPath } from 'lodash'
import type { Structure } from './types'

function createDeleteInWithCleanUp<DIM, DIL>({
deepEqual,
empty,
getIn,
deleteIn,
setIn
}: Structure<DIM, DIL>) {
const deleteInWithCleanUp = (state: DIM | DIL, path: string): DIM | DIL => {
if (path[path.length - 1] === ']') {
// array path
const pathTokens = toPath(path)
pathTokens.pop()
const parent = getIn(state, pathTokens.join('.'))
return parent ? setIn(state, path) : state
}
type ShouldDelete<SDM, SDL> = (
structure: Structure<SDM, SDL>
) => (state: SDM | SDL, path: string) => boolean

let result: DIM | DIL = state
if (getIn(state, path) !== undefined) {
result = deleteIn(state, path)
}
function createCreateDeleteInWithCleanUp<DIM, DIL>(
structure: Structure<DIM, DIL>
) {
const shouldDeleteDefault: ShouldDelete<DIM, DIL> = structure => (
state,
path
) => structure.getIn(state, path) !== undefined

const { deepEqual, empty, getIn, deleteIn, setIn } = structure

return (
shouldDelete: ShouldDelete<DIM, DIL> = shouldDeleteDefault
): DIM | DIL => {
const deleteInWithCleanUp = (state: DIM | DIL, path: string): DIM | DIL => {
if (path[path.length - 1] === ']') {
// array path
const pathTokens = toPath(path)
pathTokens.pop()
const parent = getIn(state, pathTokens.join('.'))
return parent ? setIn(state, path) : state
}

const dotIndex = path.lastIndexOf('.')
if (dotIndex > 0) {
const parentPath = path.substring(0, dotIndex)
if (parentPath[parentPath.length - 1] !== ']') {
const parent = getIn(result, parentPath)
if (deepEqual(parent, empty)) {
return deleteInWithCleanUp(result, parentPath)
let result: DIM | DIL = state

if (shouldDelete(structure)(state, path)) {
result = deleteIn(state, path)
}

const dotIndex = path.lastIndexOf('.')
if (dotIndex > 0) {
const parentPath = path.substring(0, dotIndex)
if (parentPath[parentPath.length - 1] !== ']') {
const parent = getIn(result, parentPath)
if (deepEqual(parent, empty)) {
return deleteInWithCleanUp(result, parentPath)
}
}
}
return result
}
return result
}

return deleteInWithCleanUp
return deleteInWithCleanUp
}
}

export default createDeleteInWithCleanUp
export default createCreateDeleteInWithCleanUp

0 comments on commit a97606f

Please sign in to comment.