Skip to content

Commit f7d9864

Browse files
authored
fix(database): before and after are deeply merged (#125)
1 parent cc2d227 commit f7d9864

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

src/firebase_functions/db_fn.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def _db_endpoint_handler(
9191
after = event_data["delta"]
9292
# Merge delta into data to generate an 'after' view of the data.
9393
if isinstance(before, dict) and isinstance(after, dict):
94-
after = _util.prune_nones({**before, **after})
94+
after = _util.prune_nones(_util.deep_merge(before, after))
9595
database_event_data = Change(
9696
before=before,
9797
after=after,

src/firebase_functions/private/util.py

+11
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ def prune_nones(obj: dict) -> dict:
7777
return obj
7878

7979

80+
def deep_merge(dict1, dict2):
81+
result = dict1.copy()
82+
for key, value in dict2.items():
83+
if isinstance(value, dict):
84+
node = result.get(key, {})
85+
result[key] = deep_merge(node, value)
86+
else:
87+
result[key] = value
88+
return result
89+
90+
8091
def valid_on_call_request(request: _Request) -> bool:
8192
"""Validate request"""
8293
if (_on_call_valid_method(request) and

tests/test_util.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
Internal utils tests.
1616
"""
1717
from os import environ, path
18-
from firebase_functions.private.util import firebase_config, microsecond_timestamp_conversion, nanoseconds_timestamp_conversion, is_precision_timestamp, normalize_path
18+
from firebase_functions.private.util import firebase_config, microsecond_timestamp_conversion, nanoseconds_timestamp_conversion, is_precision_timestamp, normalize_path, deep_merge
1919
import datetime as _dt
2020

2121
test_bucket = "python-functions-testing.appspot.com"
@@ -121,3 +121,27 @@ def test_normalize_document_path():
121121
test_path2 = "test/document"
122122
assert normalize_path(test_path2) == "test/document", (
123123
"Failure, path should not be changed if it is already normalized.")
124+
125+
126+
def test_toplevel_keys():
127+
dict1 = {"baz": {"answer": 42, "qux": "quux"}, "foo": "bar"}
128+
dict2 = {"baz": {"answer": 33}}
129+
result = deep_merge(dict1, dict2)
130+
assert "foo" in result
131+
assert "baz" in result
132+
133+
134+
def test_nested_merge():
135+
dict1 = {"baz": {"answer": 42, "qux": "quux"}, "foo": "bar"}
136+
dict2 = {"baz": {"answer": 33}}
137+
result = deep_merge(dict1, dict2)
138+
assert result["baz"]["answer"] == 33
139+
assert result["baz"]["qux"] == "quux"
140+
141+
142+
def test_does_not_modify_originals():
143+
dict1 = {"baz": {"answer": 42, "qux": "quux"}, "foo": "bar"}
144+
dict2 = {"baz": {"answer": 33}}
145+
deep_merge(dict1, dict2)
146+
assert dict1["baz"]["answer"] == 42
147+
assert dict2["baz"]["answer"] == 33

0 commit comments

Comments
 (0)