from fastapi import Depends, HTTPException, Response, status from inspect import Parameter, Signature from ormantic.exceptions import NoMatch from sqlite3 import IntegrityError def CRUDMapper(app, ORMClass): name = ORMClass.Mapping.table_name collection_path = '/%ss' % name item_path = '/%ss/{id}' % name @app.get(collection_path) async def read_all(): return await ORMClass.objects.all() @app.post(collection_path, status_code=status.HTTP_201_CREATED) async def create(values: ORMClass, response: Response): try: item = await ORMClass.objects.create(**values.__dict__) response.headers['Location'] = '%ss/%d' % (name, item.id) return item except IntegrityError: raise HTTPException(status_code=status.HTTP_409_CONFLICT) async def get_item(id: int): try: return await ORMClass.objects.get(id=id) except NoMatch: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) @app.get(item_path) async def read(item=Depends(get_item)): return item @app.put(item_path, status_code=status.HTTP_204_NO_CONTENT) async def update(values: ORMClass, item=Depends(get_item)): await item.update(**values.__dict__) @app.delete(item_path, status_code=status.HTTP_204_NO_CONTENT) async def delete(item=Depends(get_item)): await item.delete() def RelationshipMapper(app, ORMClass1, ORMClass2, ORMRelationship): scope_name = ORMClass1.Mapping.table_name item_name = ORMClass2.Mapping.table_name collection_path = '/%ss/{id}/%ss' % (scope_name, item_name) item_path = '/%ss/{id}/%ss/{id2}' % (scope_name, item_name) async def get_scope(id: int): try: return await ORMClass1.objects.get(id=id) except NoMatch: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) async def get_item(**kwargs): try: return await ORMClass2.objects.get(id=kwargs['%s_id' % item_name]) except NoMatch: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY) get_item.__signature__ = Signature(parameters=[Parameter( '%s_id' % item_name, Parameter.KEYWORD_ONLY, annotation=int)]) async def get_relationship(id2: int, scope=Depends(get_scope)): try: return await ORMRelationship.objects.select_related(item_name) \ .get(id=id2, **{scope_name: scope}) except NoMatch: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) @app.get(collection_path) async def read_all(scope=Depends(get_scope)): return await ORMRelationship.objects.select_related(item_name) \ .filter(**{scope_name: scope}).all() @app.post(collection_path, status_code=status.HTTP_201_CREATED) async def create( response: Response, scope=Depends(get_scope), item=Depends(get_item)): try: relationship = await ORMRelationship.objects.create( **{scope_name: scope, item_name: item}) response.headers['Location'] = \ '%ss/%d' % (item_name, relationship.id) return relationship except IntegrityError: raise HTTPException(status_code=status.HTTP_409_CONFLICT) @app.get(item_path) async def read(relationship=Depends(get_relationship)): return relationship @app.put(item_path, status_code=status.HTTP_204_NO_CONTENT) async def update( item=Depends(get_item), relationship=Depends(get_relationship)): await relationship.update(**{item_name: item.id}) @app.delete(item_path, status_code=status.HTTP_204_NO_CONTENT) async def delete(relationship=Depends(get_relationship)): await relationship.delete()