googleapis / googleapis/google-cloud-python

SpannerDialect does not accept json_serializer / json_deserializer kwargs from create_engine()

Đang mở
#15,672 1 bình luận 0 reaction 1 người được giao Được @olavloite nhận Xem trên GitHub
api: spanner
Ngôn ngữ chính
Python
Star
5.4k
Fork
1.8k
Merge trung bình
3 ngày 4 giờ
Pull request đã merge (30 ngày)
122

Mô tả

## Problem

SQLAlchemy's `create_engine()` supports `json_serializer` and `json_deserializer` parameters to customize how JSON columns are serialized/deserialized. This is [documented behavior](https://docs.sqlalchemy.org/en/20/core/type_basics.html#sqlalchemy.types.JSON) and works with PostgreSQL, MySQL, SQLite, and other dialects.

However, passing these to the Spanner dialect raises `TypeError`:

```python
engine = create_engine(
"spanner:///projects/p/instances/i/databases/d",
json_serializer=lambda obj: json.dumps(obj, cls=MyEncoder),
)
# TypeError: Invalid argument(s) 'json_serializer' sent to create_engine(),
# using configuration SpannerDialect/QueuePool/Engine.
```

### Root cause

SQLAlchemy's `create_engine()` uses `util.get_cls_kwargs()` to determine which kwargs the dialect accepts. Since `SpannerDialect.__init__` does not declare `json_serializer` or `json_deserializer`, they are rejected.

Other dialects (e.g., `PGDialect`) accept these in their `__init__` and store them on the instance, where `DefaultDialect` exposes them as `_json_serializer` / `_json_deserializer` for use by `JSON.bind_processor()`.

### Additional complexity

Even if the dialect accepted the kwargs, there's a pipeline mismatch. SQLAlchemy expects `_json_serializer` to be a `json.dumps`-like callable (returns a string), but the Spanner dialect sets `_json_serializer = JsonObject` — a class constructor that produces a `JsonObject` instance. The actual string serialization happens later in `_helpers._make_param_value_pb` when it calls `obj.serialize()`.

A proposed fix uses a **serialize-then-wrap** strategy: pre-serialize with the user's function, then `JsonObject.from_str()` the result. This requires no changes to `JsonObject` or the core `google-cloud-spanner` library.

## Expected behavior

```python
engine = create_engine(
"spanner:///...",
json_serializer=lambda obj: json.dumps(obj, default=my_handler),
)
```

should work, allowing custom types in JSON columns to be serialized correctly through the DML path.

## Environment

- `sqlalchemy-spanner`: 1.7.0
- `sqlalchemy`: 2.0.x
- `google-cloud-spanner`: 3.x

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.