Skip to content

Commit

Permalink
Merge pull request #1 from tjni/vb/handle-null-chars
Browse files Browse the repository at this point in the history
checkpoint-mysql: handle null chars in metadata
  • Loading branch information
tjni authored Oct 3, 2024
2 parents c8a359b + aab23af commit bfd00d9
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 1 deletion.
3 changes: 2 additions & 1 deletion langgraph/checkpoint/mysql/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ def _load_metadata(self, metadata: str) -> CheckpointMetadata:

def _dump_metadata(self, metadata: CheckpointMetadata) -> str:
serialized_metadata = self.jsonplus_serde.dumps(metadata)
return serialized_metadata.decode()
# NOTE: we're using JSON serializer (not msgpack), so we need to remove null characters before writing
return serialized_metadata.decode().replace("\\u0000", "")

def get_next_version(self, current: Optional[str], channel: ChannelProtocol) -> str:
if current is None:
Expand Down
10 changes: 10 additions & 0 deletions tests/test_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ async def test_asearch(self) -> None:

# TODO: test before and limit params

async def test_null_chars(self) -> None:
async with AIOMySQLSaver.from_conn_string(DEFAULT_URI) as saver:
config = await saver.aput(
self.config_1, self.chkpnt_1, {"my_key": "\x00abc"}, {}
)
assert (await saver.aget_tuple(config)).metadata["my_key"] == "abc"
assert [c async for c in saver.alist(None, filter={"my_key": "abc"})][
0
].metadata["my_key"] == "abc"

async def test_write_and_read_pending_writes_and_sends(self) -> None:
async with AIOMySQLSaver.from_conn_string(DEFAULT_URI) as saver:
config: RunnableConfig = {
Expand Down
9 changes: 9 additions & 0 deletions tests/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ def test_search(self) -> None:

# TODO: test before and limit params

def test_null_chars(self) -> None:
with PyMySQLSaver.from_conn_string(DEFAULT_URI) as saver:
config = saver.put(self.config_1, self.chkpnt_1, {"my_key": "\x00abc"}, {})
assert saver.get_tuple(config).metadata["my_key"] == "abc"
assert (
list(saver.list(None, filter={"my_key": "abc"}))[0].metadata["my_key"]
== "abc"
)

def test_write_and_read_pending_writes_and_sends(self) -> None:
with PyMySQLSaver.from_conn_string(DEFAULT_URI) as saver:
config: RunnableConfig = {
Expand Down

0 comments on commit bfd00d9

Please sign in to comment.