googleapis / googleapis/google-cloud-python

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

未关闭
#15,672 1 条评论 0 个 reaction 已指派 1 人 已被 @olavloite 认领 在 GitHub 查看
api: spanner
主要语言
Python
星标
5.4k
派生
1.8k
平均合并
3 天 4 小时
30 天内合并 PR
122

描述

## 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

贡献指南

打开贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。