googleapis / googleapis/google-cloud-python

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

オープン
#15,672 コメント 1 件 リアクション 0 件 担当者 1 名 @olavloite が担当を希望しています GitHub で見る
api: spanner
主要言語
Python
スター
5.4k
フォーク
1.8k
平均マージ
3日 4時間
マージ済み PR(30日)
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 を短くまとめたダイジェスト。