Skip to content

Commit

Permalink
unicode fk alias fix
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaxxl committed Aug 22, 2024
1 parent 8889ff9 commit 0824ed0
Show file tree
Hide file tree
Showing 9 changed files with 25 additions and 18 deletions.
9 changes: 5 additions & 4 deletions safrs/json_encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ def to_dict(self): # pragma: no cover
return None



class _SAFRSJSONEncoder():
class _SAFRSJSONEncoder:
"""
JSON encoding for safrs objects (SAFRSBase subclasses and common types)
"""
Expand Down Expand Up @@ -150,13 +149,15 @@ def sqla_encode(obj): # pragma: no cover

class SAFRSJSONProvider(_SAFRSJSONEncoder, DefaultJSONProvider):
"""
Flask JSON encoding
Flask JSON encoding
"""

mimetype = "application/vnd.api+json"


class SAFRSJSONEncoder(_SAFRSJSONEncoder, json.JSONEncoder):
"""
Common JSON encoding
Common JSON encoding
"""

pass
2 changes: 1 addition & 1 deletion safrs/jsonapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ def get(self, **kwargs):
count = 1
if instance is not None:
links = {"self": instance._s_url}
if request.full_path.strip('?').strip('/') != instance._s_url.strip('?').strip('/'):
if request.full_path.strip("?").strip("/") != instance._s_url.strip("?").strip("/"):
links["related"] = urljoin(instance._s_url_root, request.full_path)
meta.update(dict(instance_meta=instance._s_meta()))
else:
Expand Down
1 change: 1 addition & 0 deletions safrs/jsonapi_attr.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
jsonapi_attr: custom jsonapi attributes
"""

from sqlalchemy.ext.hybrid import hybrid_property
from .swagger_doc import parse_object_doc
from typing import Any
Expand Down
4 changes: 3 additions & 1 deletion safrs/jsonapi_filters.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""
JSON:API filtering strategies
"""

from .config import get_request_param
import sqlalchemy
import safrs
from .jsonapi_attr import is_jsonapi_attr
from flask import request
from sqlalchemy.orm import joinedload, Query


def create_query(cls):
"""
Create a query for the target collection `cls`.
Expand Down Expand Up @@ -76,7 +78,7 @@ def jsonapi_filter(cls) -> Query:

for attr_name, val in filters.items():
if attr_name == "id":
attr = getattr(cls,'id',None)
attr = getattr(cls, "id", None)
if attr is None:
# todo: add support for composite pkeys using `cls.id_type.get_pks`
return cls._s_get_instance_by_id(val)
Expand Down
5 changes: 2 additions & 3 deletions safrs/jsonapi_formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ def jsonapi_sort(object_query, safrs_object):
# with a minus, in which case it MUST be descending.
sort_attr = sort_attr[1:]
attr = getattr(safrs_object, sort_attr, None)
if attr is not None and hasattr(attr, 'desc'):
if attr is not None and hasattr(attr, "desc"):
attr = attr.desc()
else:
attr = getattr(safrs_object, sort_attr, None)
if sort_attr == "id":
if attr is None:
if safrs_object.id_type.primary_keys:
attr = getattr(safrs_object, safrs_object.id_type.primary_keys[0], None) # todo: composite keys edge case
if attr is not None: # might be the case if pk is unicode
if attr is not None: # might be the case if pk is unicode
sort_attr = attr.name
else:
continue
Expand Down Expand Up @@ -250,4 +250,3 @@ def jsonapi_format_response(data=None, meta=None, links=None, errors=None, count
result["included"] = safrs.base.Included

return result

1 change: 1 addition & 0 deletions safrs/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"Content-Type: application/vnd.api+json" with any media type parameters.
This should be implemented by the app, for example using @app.before_request and @app.after_request
"""

import re
from flask import Request, abort
from werkzeug.datastructures import TypeConversionDict
Expand Down
2 changes: 1 addition & 1 deletion safrs/safrs_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class Class_API(SAFRSRestAPI):
api_class_name = f"{safrs_object._s_type}_API" # name for dynamically generated classes
RESOURCE_URL_FMT = get_config("RESOURCE_URL_FMT") # configurable resource collection url formatter
url = RESOURCE_URL_FMT.format(url_prefix, safrs_object._s_collection_name)
swagger_decorator = swagger_doc(safrs_object) if self.swaggerui_blueprint else lambda x : x
swagger_decorator = swagger_doc(safrs_object) if self.swaggerui_blueprint else lambda x: x
api_class = api_decorator(type(api_class_name, (rest_api,), properties), swagger_decorator)

safrs.log.info(f"Exposing {safrs_object._s_collection_name} on {url}, endpoint: {endpoint}")
Expand Down
2 changes: 1 addition & 1 deletion safrs/safrs_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from functools import wraps
import safrs
import flask.app
from typing import Any, Dict, Type, Union
from typing import Any, Dict, Union


class SAFRS:
Expand Down
17 changes: 10 additions & 7 deletions safrs/safrs_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class SAFRSID:
primary_keys = ["id"]
columns = None
delimiter = "_"
parent_class = None

def __new__(cls, id=None):
if id is None:
Expand Down Expand Up @@ -82,8 +83,9 @@ def get_id(cls, obj):

pk = getattr(obj, cls.primary_keys[0], None)
if pk is None:
pks = [ c.name for c in cls.columns[0].table.columns if c.primary_key ]
return cls.delimiter.join(pks)
pk_names = [obj.colname_to_attrname(c.name) for c in cls.columns[0].table.columns if c.primary_key]
values = [str(getattr(obj, pk_name)) for pk_name in pk_names]
return cls.delimiter.join(values)
return pk

@classmethod
Expand All @@ -99,15 +101,14 @@ def get_pks(cls, jsonapi_id):
else:
values = str(jsonapi_id).split(cls.delimiter)
if len(values) != len(cls.columns):
columns = [c.name for c in cls.columns]
raise ValidationError(f"PK values ({values}) do not match columns ({columns})")
raise ValidationError(f"PK values ({values}) do not match columns ({cls.columns})")
result = dict()
for pk_col, val in zip(cls.columns, values):
if not val:
if pk_col.type.python_type == int:
val = 0
try:
col_name = str(pk_col.name)
col_name = str(cls.parent_class.colname_to_attrname(pk_col.name))
result[col_name] = pk_col.type.python_type(val)
except (ValueError, TypeError): # pragma: no cover
# This may happen when val is empty '' or
Expand Down Expand Up @@ -164,9 +165,11 @@ def get_id_type(cls, Super=SAFRSID, delimiter="_"):
primary_keys = columns = ["id"]
if hasattr(cls, "__table__"):
columns = [col for col in cls.__table__.columns if col.primary_key]
primary_keys = [col.name for col in columns]
primary_keys = [cls.colname_to_attrname(col.name) for col in columns]
delimiter = getattr(cls, "delimiter", "_")
id_type_class = type(cls.__name__ + "_ID", (Super,), {"primary_keys": primary_keys, "columns": columns, "delimiter": delimiter})
id_type_class = type(
cls.__name__ + "_ID", (Super,), {"primary_keys": primary_keys, "columns": columns, "delimiter": delimiter, "parent_class": cls}
)
return id_type_class


Expand Down

0 comments on commit 0824ed0

Please sign in to comment.