insert(tx, branch, entry) {
        const { batchToken, withMutations } = tx;

        const hasId = entry.hasOwnProperty(this.idAttribute);

        let workingState = branch;

        // This will not affect string id's.
        const [newMaxId, id] = idSequencer(
            this.getMaxId(branch),
            entry[this.idAttribute]
        );
        workingState = this.setMaxId(tx, branch, newMaxId);

        const finalEntry = hasId
            ? entry
            : ops.batch.set(batchToken, this.idAttribute, id, entry);

        const indexesToAppendTo = Object.keys(workingState.indexes)
            .filter(
                (fkAttr) =>
                    entry.hasOwnProperty(fkAttr) && entry[fkAttr] !== null
            )
            .map((fkAttr) => [fkAttr, entry[fkAttr]]);

        if (withMutations) {
            ops.mutable.push(id, workingState[this.arrName]);
            ops.mutable.set(id, finalEntry, workingState[this.mapName]);
            // add id to indexes
            indexesToAppendTo.forEach(([attr, value]) => {
                const attrIndex = workingState.indexes[attr];
                if (attrIndex.hasOwnProperty(value)) {
                    ops.mutable.push(id, attrIndex[value]);
                } else {
                    ops.mutable.set(value, [id], attrIndex);
                }
            });
            return {
                state: workingState,
                created: finalEntry,
            };
        }

        const nextIndexes = ops.batch.merge(
            batchToken,
            indexesToAppendTo.reduce(
                (indexMap, [attr, value]) => {
                    indexMap[attr] = ops.batch.merge(
                        batchToken,
                        {
                            [value]: ops.batch.push(
                                batchToken,
                                id,
                                indexMap[attr][value] || []
                            ),
                        },
                        indexMap[attr]
                    );
                    return indexMap;
                },
                { ...workingState.indexes }
            ),
            workingState.indexes
        );

        const nextState = ops.batch.merge(
            batchToken,
            {
                [this.arrName]: ops.batch.push(
                    batchToken,
                    id,
                    workingState[this.arrName]
                ),
                [this.mapName]: ops.batch.merge(
                    batchToken,
                    {
                        [id]: finalEntry,
                    },
                    workingState[this.mapName]
                ),
                indexes: nextIndexes,
            },
            workingState
        );

        return {
            state: nextState,
            created: finalEntry,
        };
    }
Returns the data structure including a new object `entry`
@param  {Object} tx - transaction info
@param  {Object} branch - the data structure state
@param  {Object} entry - the object to insert
@return {Object} an object with two keys: `state` and `created`.
                 `state` is the new table state and `created` is the
                 row that was created.