1

Suppose I have the following types

interface State {
  parents: Parent[]
}
interface Parent {
  uniqueName: string
  children: Child[]
  // other props
}
interface Child { 
  uniqueName: string 
  parentName: string
  // other props
}

declare const upsert: (c:Child) => Parent[] => Parent[]

I want to write the last function, upsert. Is there a canonical way of doing this functionally, where given a child (might be a new child or a modified child, the function will look through each parent, and update a matching child (match by uniqueName) or insert the input child if no matching child is found?

The update part is simple optics:

const update = child => 
  parentTraversal
  .filter(matchesNameOf(child.parent))
  .composeLens(_children)
  .composeTraversal(childTraversal)
  .filter(matchesNameOf(child))
  .set(child)(state.parents)

The insert part is a combination:

const insert = child => 
  parentTraversal
  .filter(matchesNameOf(child.parent))
  .composeLens(_children)
  .modify(cs => snoc(cs, child))(state.parents)

If I know ahead of time whether I'm updating or inserting, then I could just do

if(isNew) insert(child)(state)
else update(child)(state)

But is there a completely functional way to combine these, especially if you do not know ahead of time whether it's an update or insert?

Edit At the request of a commenter, I'll specify:

declare const _children: Lens<Parent,Child[]>
declare const parentTraversal: Traversal<Parent>
declare const childTraversal: Traversal<Child>
declare const matchesNameOf: <A extends {name:string}>(a:A) => (b:A) => boolean

and then filter, composeTraversal, composeLens, set, and modify are the standard optics functions belonging to lenses and traversals

3
  • 2
    Please provide all your code. Where are the definitions of parentTraversal, childTraversal, matchesNameOf, _children, composeLens, composeTraversal, set, modify, etc? Please provide a minimal workable example. Commented Apr 13, 2021 at 2:59
  • Oh whoops, I didn't specify I'm using fp-ts. Half of what you're asking about are built in functions for that library! Commented Apr 15, 2021 at 0:51
  • But I'm not asking for my code to be corrected, so a minimal reproducible example seems unnecessary. I'm asking for how to do something and providing code merely to show what I've tried. It's akin to me asking if there's a monad that represents nullability/optionality, and how you don't need a minimal reproducible example to answer ("yes, the Maybe monad") My code is rock solid and works. But I'm asking if there's a canonical way to do an upsert using optics. (Apparently the answer might be related to an achromatic lens, which can create as well as update) Commented Apr 15, 2021 at 0:56

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.