Skip to content

Commit b5879bc

Browse files
committed
added fields tests for other crud operations
1 parent 1129801 commit b5879bc

File tree

4 files changed

+133
-13
lines changed

4 files changed

+133
-13
lines changed

fastapi_jsonapi/views/detail_view.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
BaseJSONAPIItemInSchema,
1313
JSONAPIResultDetailSchema,
1414
)
15+
from fastapi_jsonapi.views.utils import handle_jsonapi_fields
1516
from fastapi_jsonapi.views.view_base import ViewBase
1617

1718
if TYPE_CHECKING:
@@ -34,22 +35,24 @@ async def handle_get_resource_detail(
3435
self,
3536
object_id: Union[int, str],
3637
**extra_view_deps,
37-
):
38+
) -> Union[JSONAPIResultDetailSchema, Dict]:
3839
dl: "BaseDataLayer" = await self.get_data_layer(extra_view_deps)
3940

4041
view_kwargs = {dl.url_id_field: object_id}
4142
db_object = await dl.get_object(view_kwargs=view_kwargs, qs=self.query_params)
4243

43-
return self._build_detail_response(db_object)
44+
response = self._build_detail_response(db_object)
45+
return handle_jsonapi_fields(response, self.query_params, self.jsonapi)
4446

4547
async def handle_update_resource(
4648
self,
4749
obj_id: str,
4850
data_update: BaseJSONAPIItemInSchema,
4951
**extra_view_deps,
50-
) -> JSONAPIResultDetailSchema:
52+
) -> Union[JSONAPIResultDetailSchema, Dict]:
5153
dl: "BaseDataLayer" = await self.get_data_layer(extra_view_deps)
52-
return await self.process_update_object(dl=dl, obj_id=obj_id, data_update=data_update)
54+
response = await self.process_update_object(dl=dl, obj_id=obj_id, data_update=data_update)
55+
return handle_jsonapi_fields(response, self.query_params, self.jsonapi)
5356

5457
async def process_update_object(
5558
self,

fastapi_jsonapi/views/list_view.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
JSONAPIResultDetailSchema,
77
JSONAPIResultListSchema,
88
)
9-
from fastapi_jsonapi.views.utils import handle_fields
9+
from fastapi_jsonapi.views.utils import handle_jsonapi_fields
1010
from fastapi_jsonapi.views.view_base import ViewBase
1111

1212
if TYPE_CHECKING:
@@ -42,15 +42,16 @@ async def handle_get_resource_list(self, **extra_view_deps) -> Union[JSONAPIResu
4242
total_pages = self._calculate_total_pages(count)
4343

4444
response = self._build_list_response(items_from_db, count, total_pages)
45-
return handle_fields(response, query_params, self.jsonapi)
45+
return handle_jsonapi_fields(response, query_params, self.jsonapi)
4646

4747
async def handle_post_resource_list(
4848
self,
4949
data_create: BaseJSONAPIItemInSchema,
5050
**extra_view_deps,
51-
) -> JSONAPIResultDetailSchema:
51+
) -> Union[JSONAPIResultDetailSchema, Dict]:
5252
dl: "BaseDataLayer" = await self.get_data_layer(extra_view_deps)
53-
return await self.process_create_object(dl=dl, data_create=data_create)
53+
response = await self.process_create_object(dl=dl, data_create=data_create)
54+
return handle_jsonapi_fields(response, self.query_params, self.jsonapi)
5455

5556
async def process_create_object(self, dl: "BaseDataLayer", data_create: BaseJSONAPIItemInSchema):
5657
created_object = await dl.create_object(data_create=data_create, view_kwargs={})
@@ -70,4 +71,5 @@ async def handle_delete_resource_list(self, **extra_view_deps) -> JSONAPIResultL
7071

7172
await dl.delete_objects(items_from_db, {})
7273

73-
return self._build_list_response(items_from_db, count, total_pages)
74+
response = self._build_list_response(items_from_db, count, total_pages)
75+
return handle_jsonapi_fields(response, self.query_params, self.jsonapi)

fastapi_jsonapi/views/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def _calculate_exclude_fields(
140140
return exclude_params
141141

142142

143-
def handle_fields(
143+
def handle_jsonapi_fields(
144144
response: JSONAPIResponse,
145145
query_params: QueryStringManager,
146146
jsonapi: RoutersJSONAPI,
@@ -151,6 +151,6 @@ def handle_fields(
151151
exclude_params = _calculate_exclude_fields(response, query_params, jsonapi)
152152

153153
if exclude_params:
154-
return response.dict(exclude=exclude_params)
154+
return response.dict(exclude=exclude_params, by_alias=True)
155155

156156
return response

tests/test_api/test_api_sqla_with_includes.py

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ async def test_select_custom_fields(
207207
},
208208
],
209209
"jsonapi": {"version": "1.0"},
210-
"meta": {"count": 2, "total_pages": 1},
210+
"meta": {"count": 2, "totalPages": 1},
211211
}
212212

213213
async def test_select_custom_fields_with_includes(
@@ -277,7 +277,7 @@ async def test_select_custom_fields_with_includes(
277277
},
278278
],
279279
"jsonapi": {"version": "1.0"},
280-
"meta": {"count": 2, "total_pages": 1},
280+
"meta": {"count": 2, "totalPages": 1},
281281
"included": sorted(
282282
[
283283
{
@@ -780,6 +780,32 @@ async def test_many_to_many_load_inner_includes_to_parents(
780780
assert ("child", ViewBase.get_db_item_id(child_4)) not in included_data
781781

782782

783+
class TestGetUserDetail:
784+
def get_url(self, app: FastAPI, user_id: int) -> str:
785+
return app.url_path_for("get_user_detail", obj_id=user_id)
786+
787+
async def test_select_custom_fields(
788+
self,
789+
app: FastAPI,
790+
client: AsyncClient,
791+
user_1: User,
792+
):
793+
url = self.get_url(app, user_1.id)
794+
params = QueryParams([("fields[user]", "name,age")])
795+
response = await client.get(url, params=params)
796+
797+
assert response.status_code == status.HTTP_200_OK
798+
assert response.json() == {
799+
"data": {
800+
"attributes": UserAttributesBaseSchema.from_orm(user_1).dict(include={"name", "age"}),
801+
"id": str(user_1.id),
802+
"type": "user",
803+
},
804+
"jsonapi": {"version": "1.0"},
805+
"meta": None,
806+
}
807+
808+
783809
class TestUserWithPostsWithInnerIncludes:
784810
@mark.parametrize(
785811
"include, expected_relationships_inner_relations, expect_user_include",
@@ -1503,6 +1529,34 @@ class ContainsTimestampAttrsSchema(BaseModel):
15031529
"data": [],
15041530
}
15051531

1532+
async def test_select_custom_fields(self, app: FastAPI, client: AsyncClient):
1533+
user_attrs_schema = UserAttributesBaseSchema(
1534+
name=fake.name(),
1535+
age=fake.pyint(),
1536+
email=fake.email(),
1537+
)
1538+
create_user_body = {
1539+
"data": {
1540+
"attributes": user_attrs_schema.dict(),
1541+
},
1542+
}
1543+
params = QueryParams([("fields[user]", "name")])
1544+
url = app.url_path_for("get_user_list")
1545+
res = await client.post(url, json=create_user_body, params=params)
1546+
assert res.status_code == status.HTTP_201_CREATED, res.text
1547+
response_data: dict = res.json()
1548+
1549+
assert "data" in response_data
1550+
assert response_data["data"].pop("id")
1551+
assert response_data == {
1552+
"data": {
1553+
"attributes": user_attrs_schema.dict(include={"name"}),
1554+
"type": "user",
1555+
},
1556+
"jsonapi": {"version": "1.0"},
1557+
"meta": None,
1558+
}
1559+
15061560

15071561
class TestPatchObjects:
15081562
async def test_patch_object(
@@ -1615,6 +1669,39 @@ async def test_update_schema_has_extra_fields(self, user_1: User, caplog):
16151669
):
16161670
assert expected in log_message
16171671

1672+
async def test_select_custom_fields(
1673+
self,
1674+
app: FastAPI,
1675+
client: AsyncClient,
1676+
user_1: User,
1677+
):
1678+
new_attrs = UserAttributesBaseSchema(
1679+
name=fake.name(),
1680+
age=fake.pyint(),
1681+
email=fake.email(),
1682+
)
1683+
1684+
patch_user_body = {
1685+
"data": {
1686+
"id": user_1.id,
1687+
"attributes": new_attrs.dict(),
1688+
},
1689+
}
1690+
params = QueryParams([("fields[user]", "name")])
1691+
url = app.url_path_for("get_user_detail", obj_id=user_1.id)
1692+
res = await client.patch(url, params=params, json=patch_user_body)
1693+
1694+
assert res.status_code == status.HTTP_200_OK, res.text
1695+
assert res.json() == {
1696+
"data": {
1697+
"attributes": new_attrs.dict(include={"name"}),
1698+
"id": str(user_1.id),
1699+
"type": "user",
1700+
},
1701+
"jsonapi": {"version": "1.0"},
1702+
"meta": None,
1703+
}
1704+
16181705

16191706
class TestPatchObjectRelationshipsToOne:
16201707
async def test_ok_when_foreign_key_of_related_object_is_nullable(
@@ -2085,6 +2172,34 @@ async def test_delete_objects_many(
20852172
"meta": {"count": 1, "totalPages": 1},
20862173
}
20872174

2175+
async def test_select_custom_fields(
2176+
self,
2177+
app: FastAPI,
2178+
client: AsyncClient,
2179+
user_1: User,
2180+
user_2: User,
2181+
):
2182+
params = QueryParams([("fields[user]", "name")])
2183+
url = app.url_path_for("get_user_list")
2184+
res = await client.delete(url, params=params)
2185+
assert res.status_code == status.HTTP_200_OK, res.text
2186+
assert res.json() == {
2187+
"data": [
2188+
{
2189+
"attributes": UserAttributesBaseSchema.from_orm(user_1).dict(include={"name"}),
2190+
"id": str(user_1.id),
2191+
"type": "user",
2192+
},
2193+
{
2194+
"attributes": UserAttributesBaseSchema.from_orm(user_2).dict(include={"name"}),
2195+
"id": str(user_2.id),
2196+
"type": "user",
2197+
},
2198+
],
2199+
"jsonapi": {"version": "1.0"},
2200+
"meta": {"count": 2, "totalPages": 1},
2201+
}
2202+
20882203

20892204
class TestOpenApi:
20902205
def test_openapi_method_ok(self, app: FastAPI):

0 commit comments

Comments
 (0)