langgraph-checkpoint-postgres 1.0.10__tar.gz → 1.0.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/PKG-INFO +1 -1
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/langgraph/store/postgres/aio.py +28 -4
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/langgraph/store/postgres/base.py +47 -6
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/pyproject.toml +1 -1
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/README.md +0 -0
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/langgraph/checkpoint/postgres/__init__.py +0 -0
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/langgraph/checkpoint/postgres/aio.py +0 -0
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/langgraph/checkpoint/postgres/base.py +0 -0
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/langgraph/checkpoint/py.typed +0 -0
- {langgraph_checkpoint_postgres-1.0.10 → langgraph_checkpoint_postgres-1.0.11}/langgraph/store/postgres/__init__.py +0 -0
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
3
|
from contextlib import asynccontextmanager
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import (
|
|
5
|
+
Any,
|
|
6
|
+
AsyncIterator,
|
|
7
|
+
Callable,
|
|
8
|
+
Iterable,
|
|
9
|
+
Optional,
|
|
10
|
+
Sequence,
|
|
11
|
+
Union,
|
|
12
|
+
cast,
|
|
13
|
+
)
|
|
5
14
|
|
|
15
|
+
import orjson
|
|
6
16
|
from psycopg import AsyncConnection, AsyncCursor
|
|
7
17
|
from psycopg.errors import UndefinedTable
|
|
8
18
|
from psycopg.rows import dict_row
|
|
@@ -19,7 +29,16 @@ logger = logging.getLogger(__name__)
|
|
|
19
29
|
|
|
20
30
|
|
|
21
31
|
class AsyncPostgresStore(BasePostgresStore[AsyncConnection]):
|
|
22
|
-
def __init__(
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
conn: AsyncConnection[Any],
|
|
35
|
+
*,
|
|
36
|
+
deserializer: Optional[
|
|
37
|
+
Callable[[Union[bytes, orjson.Fragment]], dict[str, Any]]
|
|
38
|
+
] = None,
|
|
39
|
+
) -> None:
|
|
40
|
+
super().__init__(deserializer=deserializer)
|
|
41
|
+
self.conn = conn
|
|
23
42
|
self.conn = conn
|
|
24
43
|
self.loop = asyncio.get_running_loop()
|
|
25
44
|
|
|
@@ -87,7 +106,9 @@ class AsyncPostgresStore(BasePostgresStore[AsyncConnection]):
|
|
|
87
106
|
for idx, key in items:
|
|
88
107
|
row = key_to_row.get(key)
|
|
89
108
|
if row:
|
|
90
|
-
results[idx] = _row_to_item(
|
|
109
|
+
results[idx] = _row_to_item(
|
|
110
|
+
namespace, row, loader=self._deserializer
|
|
111
|
+
)
|
|
91
112
|
else:
|
|
92
113
|
results[idx] = None
|
|
93
114
|
|
|
@@ -115,7 +136,10 @@ class AsyncPostgresStore(BasePostgresStore[AsyncConnection]):
|
|
|
115
136
|
|
|
116
137
|
for cur, idx, op in cursors:
|
|
117
138
|
rows = cast(list[Row], await cur.fetchall())
|
|
118
|
-
items = [
|
|
139
|
+
items = [
|
|
140
|
+
_row_to_item(op.namespace_prefix, row, loader=self._deserializer)
|
|
141
|
+
for row in rows
|
|
142
|
+
]
|
|
119
143
|
results[idx] = items
|
|
120
144
|
|
|
121
145
|
async def _batch_list_namespaces_ops(
|
|
@@ -4,7 +4,18 @@ import logging
|
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
from contextlib import contextmanager
|
|
6
6
|
from datetime import datetime
|
|
7
|
-
from typing import
|
|
7
|
+
from typing import (
|
|
8
|
+
Any,
|
|
9
|
+
Callable,
|
|
10
|
+
Generic,
|
|
11
|
+
Iterable,
|
|
12
|
+
Iterator,
|
|
13
|
+
Optional,
|
|
14
|
+
Sequence,
|
|
15
|
+
TypeVar,
|
|
16
|
+
Union,
|
|
17
|
+
cast,
|
|
18
|
+
)
|
|
8
19
|
|
|
9
20
|
import orjson
|
|
10
21
|
from psycopg import BaseConnection, Connection, Cursor
|
|
@@ -54,6 +65,17 @@ C = TypeVar("C", bound=BaseConnection)
|
|
|
54
65
|
class BasePostgresStore(BaseStore, Generic[C]):
|
|
55
66
|
MIGRATIONS = MIGRATIONS
|
|
56
67
|
conn: C
|
|
68
|
+
__slots__ = ("_deserializer",)
|
|
69
|
+
|
|
70
|
+
def __init__(
|
|
71
|
+
self,
|
|
72
|
+
*,
|
|
73
|
+
deserializer: Optional[
|
|
74
|
+
Callable[[Union[bytes, orjson.Fragment]], dict[str, Any]]
|
|
75
|
+
] = None,
|
|
76
|
+
) -> None:
|
|
77
|
+
super().__init__()
|
|
78
|
+
self._deserializer = deserializer
|
|
57
79
|
|
|
58
80
|
def _get_batch_GET_ops_queries(
|
|
59
81
|
self,
|
|
@@ -191,7 +213,15 @@ class BasePostgresStore(BaseStore, Generic[C]):
|
|
|
191
213
|
|
|
192
214
|
|
|
193
215
|
class PostgresStore(BasePostgresStore[Connection]):
|
|
194
|
-
def __init__(
|
|
216
|
+
def __init__(
|
|
217
|
+
self,
|
|
218
|
+
conn: Connection[Any],
|
|
219
|
+
*,
|
|
220
|
+
deserializer: Optional[
|
|
221
|
+
Callable[[Union[bytes, orjson.Fragment]], dict[str, Any]]
|
|
222
|
+
] = None,
|
|
223
|
+
) -> None:
|
|
224
|
+
super().__init__(deserializer=deserializer)
|
|
195
225
|
self.conn = conn
|
|
196
226
|
|
|
197
227
|
def batch(self, ops: Iterable[Op]) -> list[Result]:
|
|
@@ -246,7 +276,9 @@ class PostgresStore(BasePostgresStore[Connection]):
|
|
|
246
276
|
for idx, key in items:
|
|
247
277
|
row = key_to_row.get(key)
|
|
248
278
|
if row:
|
|
249
|
-
results[idx] = _row_to_item(
|
|
279
|
+
results[idx] = _row_to_item(
|
|
280
|
+
namespace, row, loader=self._deserializer
|
|
281
|
+
)
|
|
250
282
|
else:
|
|
251
283
|
results[idx] = None
|
|
252
284
|
|
|
@@ -274,7 +306,10 @@ class PostgresStore(BasePostgresStore[Connection]):
|
|
|
274
306
|
|
|
275
307
|
for cur, idx, op in cursors:
|
|
276
308
|
rows = cast(list[Row], cur.fetchall())
|
|
277
|
-
items = [
|
|
309
|
+
items = [
|
|
310
|
+
_row_to_item(op.namespace_prefix, row, loader=self._deserializer)
|
|
311
|
+
for row in rows
|
|
312
|
+
]
|
|
278
313
|
results[idx] = items
|
|
279
314
|
|
|
280
315
|
def _batch_list_namespaces_ops(
|
|
@@ -361,11 +396,17 @@ def _namespace_to_ltree(namespace: tuple[str, ...]) -> str:
|
|
|
361
396
|
return ".".join(namespace)
|
|
362
397
|
|
|
363
398
|
|
|
364
|
-
def _row_to_item(
|
|
399
|
+
def _row_to_item(
|
|
400
|
+
namespace: tuple[str, ...],
|
|
401
|
+
row: Row,
|
|
402
|
+
*,
|
|
403
|
+
loader: Optional[Callable[[Union[bytes, orjson.Fragment]], dict[str, Any]]] = None,
|
|
404
|
+
) -> Item:
|
|
365
405
|
"""Convert a row from the database into an Item."""
|
|
406
|
+
loader = loader or _json_loads
|
|
366
407
|
val = row["value"]
|
|
367
408
|
return Item(
|
|
368
|
-
value=val if isinstance(val, dict) else
|
|
409
|
+
value=val if isinstance(val, dict) else loader(val),
|
|
369
410
|
key=row["key"],
|
|
370
411
|
namespace=namespace,
|
|
371
412
|
created_at=row["created_at"],
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|