Optimize the internal implementation of serializers (#419)

This commit is contained in:
Wu Clan
2024-09-11 16:40:05 +08:00
committed by GitHub
parent ac8e4a0406
commit f5b7de6910

View File

@ -3,9 +3,10 @@
from decimal import Decimal from decimal import Decimal
from typing import Any, Sequence, TypeVar from typing import Any, Sequence, TypeVar
import msgspec from fastapi.encoders import decimal_encoder
from msgspec import json
from sqlalchemy import Row, RowMapping from sqlalchemy import Row, RowMapping
from sqlalchemy.orm import ColumnProperty, SynonymProperty, class_mapper
from starlette.responses import JSONResponse from starlette.responses import JSONResponse
RowData = Row | RowMapping | Any RowData = Row | RowMapping | Any
@ -20,15 +21,13 @@ def select_columns_serialize(row: R) -> dict:
:param row: :param row:
:return: :return:
""" """
obj_dict = {} result = {}
for column in row.__table__.columns.keys(): for column in row.__table__.columns.keys():
val = getattr(row, column) v = getattr(row, column)
if isinstance(val, Decimal): if isinstance(v, Decimal):
if val % 1 == 0: v = decimal_encoder(v)
val = int(val) result[column] = v
val = float(val) return result
obj_dict[column] = val
return obj_dict
def select_list_serialize(row: Sequence[R]) -> list: def select_list_serialize(row: Sequence[R]) -> list:
@ -38,22 +37,35 @@ def select_list_serialize(row: Sequence[R]) -> list:
:param row: :param row:
:return: :return:
""" """
ret_list = [select_columns_serialize(_) for _ in row] result = [select_columns_serialize(_) for _ in row]
return ret_list return result
def select_as_dict(row: R) -> dict: def select_as_dict(row: R, use_alias: bool = False) -> dict:
""" """
Converting SQLAlchemy select to dict, which can contain relational data, Converting SQLAlchemy select to dict, which can contain relational data,
depends on the properties of the select object itself depends on the properties of the select object itself
If set use_alias is True, the column name will be returned as alias,
If alias doesn't exist in columns, we don't recommend setting it to True
:param row: :param row:
:param use_alias:
:return: :return:
""" """
obj_dict = row.__dict__ if not use_alias:
if '_sa_instance_state' in obj_dict: result = row.__dict__
del obj_dict['_sa_instance_state'] if '_sa_instance_state' in result:
return obj_dict del result['_sa_instance_state']
return result
else:
result = {}
mapper = class_mapper(row.__class__)
for prop in mapper.iterate_properties:
if isinstance(prop, (ColumnProperty, SynonymProperty)):
key = prop.key
result[key] = getattr(row, key)
return result
class MsgSpecJSONResponse(JSONResponse): class MsgSpecJSONResponse(JSONResponse):
@ -62,4 +74,4 @@ class MsgSpecJSONResponse(JSONResponse):
""" """
def render(self, content: Any) -> bytes: def render(self, content: Any) -> bytes:
return msgspec.json.encode(content) return json.encode(content)