async def test_update_cleaning_with_valid_input( self, app: FastAPI, authorized_client: AsyncClient, test_cleaning: CleaningInDB, attrs_to_change: List[str], values: List[str], ) -> None: cleaning_update = { attrs_to_change[i]: values[i] for i in range(len(attrs_to_change))} res = await authorized_client.put( app.url_path_for("cleanings:update-cleaning-by-id", cleaning_id=test_cleaning.id), json=cleaning_update ) assert res.status_code == status.HTTP_200_OK updated_cleaning = CleaningInDB(**res.json()) assert updated_cleaning.id == test_cleaning.id # make sure it's the same cleaning # make sure that any attribute we updated has changed to the correct value for i in range(len(attrs_to_change)): assert getattr(updated_cleaning, attrs_to_change[i]) != getattr( test_cleaning, attrs_to_change[i]) assert getattr(updated_cleaning, attrs_to_change[i]) == values[i] # make sure that no other attributes' values have changed for attr, value in updated_cleaning.dict().items(): if attr not in attrs_to_change and attr != "updated_at": assert getattr(test_cleaning, attr) == value
async def update_cleaning(self, *, cleaning: CleaningInDB, cleaning_update: CleaningUpdate) -> CleaningInDB: cleaning_update_params = cleaning.copy(update=cleaning_update.dict( exclude_unset=True)) if cleaning_update_params.cleaning_type is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid cleaning type. Cannot be None.") updated_cleaning = await self.db.fetch_one( query=UPDATE_CLEANING_BY_ID_QUERY, values=cleaning_update_params.dict( exclude={"owner", "created_at", "updated_at"}), ) return CleaningInDB(**updated_cleaning)
async def get_cleaning_by_id(self, *, id: UUID, requesting_user: UserInDB) -> CleaningInDB: cleaning = await self.db.fetch_one(query=GET_CLEANING_BY_ID_QUERY, values={"id": id}) if not cleaning: return None return CleaningInDB(**cleaning)
async def create_cleaning(self, *, new_cleaning: CleaningCreate) -> CleaningInDB: query_values = new_cleaning.dict() cleaning = await self.db.fetch_one(query=CREATE_CLEANING_QUERY, values=query_values) return CleaningInDB(**cleaning)
async def update_cleaning(self, *, update_id: int, cleaning_update: CleaningUpdate) -> CleaningInDB: cleaning = await self.get_cleaning_by_id(get_id=update_id) if not cleaning: return None cleaning_update_params = cleaning.copy(update=cleaning_update.dict( exclude_unset=True)) if cleaning_update_params.cleaning_type is None: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid cleaning type. Cannot be None.") try: updated_cleaning = await self.db.fetch_one( query=UPDATE_CLEANING_BY_ID_QUERY, values=cleaning_update_params.dict()) return CleaningInDB.parse_obj(updated_cleaning) except Exception as e: logger.error(e) raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid update params.")
async def test_get_cleaning_by_id( self, app: FastAPI, authorized_client: AsyncClient, test_cleaning: CleaningInDB ) -> None: res = await authorized_client.get(app.url_path_for("cleanings:get-cleaning-by-id", cleaning_id=test_cleaning.id)) assert res.status_code == status.HTTP_200_OK cleaning = CleaningInDB(**res.json()) assert cleaning == test_cleaning
async def list_all_user_cleanings( self, requesting_user: UserInDB) -> List[CleaningInDB]: cleaning_records = await self.db.fetch_all( query=LIST_ALL_USER_CLEANINGS_QUERY, values={"owner": requesting_user.id}) return [CleaningInDB(**l) for l in cleaning_records]
async def test_get_all_cleanings(self, app: FastAPI, client: AsyncClient, test_cleaning: CleaningInDB): res = await client.get(app.url_path_for("cleanings:get-all-cleanings")) assert res.status_code == HTTP_200_OK assert isinstance(res.json(), list) assert len(res.json()) > 0 cleanings = [CleaningInDB(**l) for l in res.json()] assert test_cleaning in cleanings
async def get_cleaning_by_id(self, *, get_id: int): cleaning = await self.db.fetch_one(query=GET_CLEANING_BY_ID_QUERY, values={"id": get_id}) if not cleaning: return None return CleaningInDB.parse_obj(cleaning)
async def create_cleaning(self, *, new_cleaning: CleaningCreate, requesting_user: UserInDB) -> CleaningInDB: cleaning = await self.db.fetch_one(query=CREATE_CLEANING_QUERY, values={ **new_cleaning.dict(), "owner": requesting_user.id }) return CleaningInDB(**cleaning)
async def get_cleaning_by_id(self, *, id: int) -> CleaningInDB: cleaning = await self.db.fetch_one(GET_CLEANING_BY_ID_QUERY, values={"id": id}) if not cleaning: return None return CleaningInDB(**cleaning)
async def populate_cleaning( self, *, cleaning: CleaningInDB, requesting_user: UserInDB = None) -> CleaningPublic: return CleaningPublic( **cleaning.dict(exclude={"owner"}), owner=await self.users_repo.get_user_by_id(user_id=cleaning.owner), # any other populated fields for cleaning public would be tacked on here )
async def test_get_cleaning_by_id(self, app: FastAPI, authorized_client: AsyncClient, test_cleaning: CleaningInDB) -> None: res = await authorized_client.get( app.url_path_for("cleanings:get-cleaning-by-id", cleaning_id=test_cleaning.id)) assert res.status_code == status.HTTP_200_OK # exclude "owner" after refactoring it to a full UserInDB cleaning = CleaningPublic(**res.json()).dict(exclude={"owner"}) assert cleaning == test_cleaning.dict(exclude={"owner"})
async def get_cleaning_by_id(self, *, id: int, requesting_user: UserInDB, populate: bool = True ) -> Union[CleaningInDB, CleaningPublic]: cleaning_record = await self.db.fetch_one( query=GET_CLEANING_BY_ID_QUERY, values={"id": id}) if cleaning_record: cleaning = CleaningInDB(**cleaning_record) if populate: return await self.populate_cleaning( cleaning=cleaning, requesting_user=requesting_user) return cleaning
async def populate_cleaning( self, *, cleaning: CleaningInDB, requesting_user: UserInDB = None) -> CleaningPublic: """ creates a model with all the attributes of the cleaning record retrieved by the GET_CLEANING_BY_ID_QUERY, but the owner field is replaced. """ return CleaningPublic( **cleaning.dict(exclude={"owner"}), owner=await self.users_repo.get_user_by_id(user_id=cleaning.owner), # any other populated fields for cleaning public would be tacked on here )
async def test_get_all_cleanings_returns_valid_response( self, app: FastAPI, client: AsyncClient, test_cleaning: CleaningInDB) -> None: res = await client.get(app.url_path_for("cleanings:get-all-cleanings")) assert res.status_code == HTTP_200_OK """ We then ensure that our response is a list, assert that the list is not empty, and coerce all returned cleanings into the shape of our CleaningInDB model. Finally, we verify that our test_cleaning fixture is present in the response. """ assert isinstance(res.json(), list) assert len(res.json()) > 0 cleanings = [CleaningInDB(**l) for l in res.json()] assert test_cleaning in cleanings
async def test_get_all_cleanings_returns_only_user_owned_cleaning( self, app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, db: Database, test_cleaning: CleaningInDB, test_cleanings_list: List[CleaningInDB], ) -> None: res = await authorized_client.get( app.url_path_for("cleanings:list-all-user-cleanings")) assert res.status_code == status.HTTP_200_OK assert isinstance(res.json(), list) assert len(res.json()) > 0 cleanings = [CleaningInDB(**obj) for obj in res.json()] assert test_cleaning in cleanings for cleaning in cleanings: assert cleaning.owner == test_user.id assert all(c not in cleanings for c in test_cleanings_list)
async def test_update_cleaning_with_valid_input( self, app: FastAPI, client: AsyncClient, sample_cleaning: CleaningInDB, attrs_to_change: List[str], values: List[Union[str, int]] ) -> None: cleaning_update = {"cleaning_update": {attrs_to_change[i]: values[i] for i, _ in enumerate(attrs_to_change)}} res = await client.put( app.url_path_for("cleanings:update-cleaning-by-id", cleaning_id=sample_cleaning.id), json=cleaning_update ) assert res.status_code == status.HTTP_200_OK updated_cleaning = CleaningInDB.parse_obj(res.json()) assert updated_cleaning.id == sample_cleaning.id # make sure that any attribute we updated has changed to the correct value for i in range(len(attrs_to_change)): assert getattr(updated_cleaning, attrs_to_change[i]) != getattr(sample_cleaning, attrs_to_change[i]) assert getattr(updated_cleaning, attrs_to_change[i]) == values[i]
async def test_get_all_cleanings_returns_only_user_owned_cleanings( self, app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, db: Database, test_cleaning: CleaningInDB, test_cleanings_list: List[CleaningInDB], ) -> None: res = await authorized_client.get(app.url_path_for("cleanings:list-all-user-cleanings")) assert res.status_code == status.HTTP_200_OK assert isinstance(res.json(), list) assert len(res.json()) > 0 cleanings = [CleaningInDB(**l) for l in res.json()] # check that a cleaning created by our user is returned assert test_cleaning in cleanings # test that all cleanings returned are owned by this user for cleaning in cleanings: assert cleaning.owner == test_user.id # assert all cleanings created by another user not included (redundant, but fine) assert all(c not in cleanings for c in test_cleanings_list)
async def update_cleaning(self, *, id: int, cleaning_update: CleaningUpdate) -> CleaningInDB: cleaning = await self.get_cleaning_by_id(id=id) if not cleaning: return None """ As specified in pydantic docs, we can call the .copy() method on the model and pass any changes we'd like to make to the update parameter. Pydantic indicates that update should be "a dictionary of values to change when creating the copied model", and we obtain that by calling the .dict() method on the CleaningUpdate model we received in our PUT route. By specifying exclude_unset=True, Pydantic will leave out any attributes that were not explicitly set when the model was created. """ cleaning_update_params = cleaning.copy(update=cleaning_update.dict( exclude_unset=True)) # Note that because we listed "cleaning_type" with an # Optional type specification in our CleaningUpdate # Any time a user pass None as the cleaning_type, # throw an error. if cleaning_update_params.cleaning_type is None: raise HTTPException( status_code=HTTP_400_BAD_REQUEST, detail="Invalid cleaning type. Cannot be None.", ) try: updated_cleaning = await self.db.fetch_one( query=UPDATE_CLEANING_BY_ID_QUERY, values=cleaning_update_params.dict()) return CleaningInDB(**updated_cleaning) except Exception as e: print(e) raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail="Invalid update params.")
async def create_cleaning(self, *, new_cleaning: CleaningCreate) -> CleaningInDB: cleaning = await self.db.fetch_one(query=CREATE_CLEANING_QUERY, values=new_cleaning.dict()) return CleaningInDB.parse_obj(cleaning)
async def test_get_cleaning_by_id(self, app: FastAPI, client: AsyncClient, sample_cleaning: CleaningInDB) -> None: res = await client.get(app.url_path_for("cleanings:get-cleaning-by-id", cleaning_id=sample_cleaning.id)) assert res.status_code == status.HTTP_200_OK cleaning = CleaningInDB.parse_obj(res.json()) assert cleaning.id == 1
async def get_all_cleanings(self) -> List[CleaningInDB]: cleanings = await self.db.fetch_all(query=GET_ALL_CLEANINGS_QUERY) return [CleaningInDB(**cleaning) for cleaning in cleanings]
async def get_all_cleanings(self) -> List[CleaningPublic]: cleaning_records = await self.db.fetch_all( query=GET_ALL_CLEANINGS_QUERY) return [CleaningInDB(**l) for l in cleaning_records]