Add `Assign` function to avoid deep merging with `Merge`

Based on a discussion in a recent help topic, I think it would be valuable to have a function, perhaps Assign, that works like Object.assign, or lodash _.assign for that matter.

This would be in addition to the already available Merge FQL function, which merges object properties recursively. Merge is similar to lodash _.merge.

Example Problem

It is desirable to replace an entire object at some path in a document. For example, how do we update the following doc

{
  data: {
    field1: true,
    field2: 'something',
    field3: {
      type: 'success',
      prop1: 'a',
      prop2: 'b'
    }
  }
}

to the following

{
  data: {
    field1: true,
    field2: 'something',
    field3: {
      type: 'error',
      message: 'ah!',
    }
  }
}

This cannot be done (pretty sure…) with a single Update call with the current API.

Desired Usage

Use new Assign function to override a data at a path.
(1 Read, 1 Write)

Update(
  ref,
  {
    data: Assign(
      Select('data', Get(ref)),
      {
        field3: {  type: 'error', message: 'ah!' }
      }
    )
  }
)

Anything at a deeper path would involve several layers of Assign calls.

Work Arounds

Option 1: update to null then update again.

(0 Reads, 2 Writes)

Do(
  Update(ref, { data: { state: null } }),
  Update(ref, {
    data: {
      state: {  type: 'error', message: 'ah!' },
    },
  }),
);

Not actually too bad, code complexity wise. Feels like doing something wrong. Twice as many Write ops. Added latency?

Option 2: Replace with reconstructed object

(1 Read, 1 Write)

Replace(
    ref,
    {
      data: {
        field1: Select(['data', 'field1'], Get(ref)),
        field2: Select(['data', 'field2'], Get(ref)),
        field3: {  type: 'error', message: 'ah!' },
      }
    }
  )

Keeps single Write. Super verbose. Requires knowledge of entire document structure – fragile to schema changes. Would be WAY to much for more complex documents.

Awesome. That’s what we need.