Skip to content

Commit

Permalink
Add MongoDB as a main database
Browse files Browse the repository at this point in the history
  • Loading branch information
spyker77 committed May 11, 2023
1 parent 045b8d2 commit 4a24aef
Show file tree
Hide file tree
Showing 27 changed files with 1,456 additions and 353 deletions.
21 changes: 21 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
###############
# Application #
###############
MONGODB_DATABASE=jelly
MONGODB_URL=mongodb://mongo:27017
ELASTICSEARCH_URL=http://elasticsearch:9200


#################
# Elasticsearch #
#################
logger.level=warn
discovery.type=single-node
xpack.security.enabled=false


##########
# Kibana #
##########
SERVER_NAME=kibana.local
ELASTICSEARCH_HOSTS=http://elasticsearch:9200
22 changes: 22 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import logging
from functools import lru_cache

from pydantic import BaseSettings

logger = logging.getLogger("gunicorn.error")


class Settings(BaseSettings):
mongodb_database: str
mongodb_url: str
elasticsearch_url: str

class Config:
env_file = ".env"
env_file_encoding = "utf-8"


@lru_cache
def get_settings() -> Settings:
logger.info("Loading config settings from the environment...")
return Settings()
File renamed without changes.
25 changes: 25 additions & 0 deletions app/database/mongodb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import logging

from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase

from ..config import get_settings

settings = get_settings()

logger = logging.getLogger("gunicorn.error")


client = AsyncIOMotorClient(settings.mongodb_url)


# async def get_db() -> AsyncIOMotorDatabase:
# db = client[settings.mongodb_database]
# try:
# yield db
# finally:
# client.close()


async def get_db() -> AsyncIOMotorDatabase:
db = client[settings.mongodb_database]
return db
12 changes: 0 additions & 12 deletions app/documents/asset.py

This file was deleted.

23 changes: 0 additions & 23 deletions app/documents/creator.py

This file was deleted.

Empty file added app/graphql/__init__.py
Empty file.
162 changes: 162 additions & 0 deletions app/graphql/mutation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import strawberry
from graphql import GraphQLError
from motor.motor_asyncio import AsyncIOMotorDatabase
from strawberry.types import Info

from ..models.asset import AssetModel
from ..models.creator import CreatorModel
from ..schemas.asset import AssetSchema
from ..schemas.creator import CreatorSchema
from ..services.creator import create_creator, delete_creator_by_email, get_creator_by_email, update_creator_assets


@strawberry.type
class Mutation:
@strawberry.mutation
async def add_creator(self, info: Info, username: str, email: str) -> CreatorSchema:
"""Mutation to add creator. Example of the GraphQL document:
```graphql
mutation {
addCreator(username: "CoolUser", email: "[email protected]") {
Id
username
email
signedUp
assets {
type
createdAt
}
}
}
```
Args:
username (str): Username of the creator.
email (str): The email of the creator.
Returns:
CreatorSchema: Data about the creator and related assets.
"""
db: AsyncIOMotorDatabase = info.context["db"]

creator = await get_creator_by_email(db, email)
if creator:
raise GraphQLError(message="Creator already exists.")

new_creator = CreatorModel(username=username, email=email).dict(by_alias=True)
result = await create_creator(db, new_creator, info.context["background_tasks"])

return CreatorSchema(**result)

@strawberry.mutation
async def add_asset_to_creator(self, info: Info, type: str, email: str) -> AssetSchema:
"""
Mutation to add asset to the creator. Example of the GraphQL document:
```graphql
mutation {
addAssetToCreator(type: "New Fancy Platform", email: "[email protected]") {
type
createdAt
}
}
```
Args:
type (str): Type of a new asset.
email (str): The email of the creator.
Returns:
AssetSchema: Data about assets of the creator.
"""
db: AsyncIOMotorDatabase = info.context["db"]

creator = await get_creator_by_email(db, email)
if not creator:
raise GraphQLError(message="Creator does not exist.")

new_asset = AssetModel(type=type).dict()
creator_assets = creator.get("assets", [])
creator_assets.append(new_asset)

await update_creator_assets(db, email, creator_assets, info.context["background_tasks"])

return AssetSchema(**new_asset)

@strawberry.mutation
async def remove_asset_from_creator(self, info: Info, type: str, email: str) -> AssetSchema:
"""
Mutation to remove an asset from the creator. Example of the GraphQL document:
```graphql
mutation {
removeAssetFromCreator(type: "New Fancy Platform", email: "[email protected]") {
type
createdAt
}
}
```
Args:
type (str): Type of the asset to remove.
email (str): The email of the creator.
Returns:
AssetSchema: Data about the removed asset.
"""
db: AsyncIOMotorDatabase = info.context["db"]

creator = await get_creator_by_email(db, email)
if not creator:
raise GraphQLError(message="Creator does not exist.")

creator_assets = creator.get("assets", [])
asset_to_remove = None

for index, asset in enumerate(creator_assets):
if asset["type"] == type:
asset_to_remove = creator_assets.pop(index)
break

if asset_to_remove is None:
raise GraphQLError(message="Asset does not exist.")

await update_creator_assets(db, email, creator_assets, info.context["background_tasks"])

return AssetSchema(**asset_to_remove)

@strawberry.mutation
async def delete_creator(self, info: Info, email: str) -> CreatorSchema:
"""Mutation to delete creator. Example of the GraphQL document:
```graphql
mutation {
deleteCreator(email: "[email protected]") {
Id
username
email
signedUp
assets {
type
createdAt
}
}
}
```
Args:
email (str): The email of the creator.
Returns:
CreatorSchema: Data about the creator that has just been deleted.
"""
db: AsyncIOMotorDatabase = info.context["db"]

creator = await get_creator_by_email(db, email)
if not creator:
raise GraphQLError(message="Creator does not exist.")

deleted_creator = await delete_creator_by_email(db, email, info.context["background_tasks"])

return CreatorSchema(**deleted_creator)
84 changes: 84 additions & 0 deletions app/graphql/query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import strawberry
from graphql import GraphQLError
from motor.motor_asyncio import AsyncIOMotorDatabase
from strawberry.types import Info

from ..schemas.creator import CreatorSchema
from ..services.creator import get_creator_by_email, search_creators


@strawberry.type
class Query:
@strawberry.field
async def get_creator(self, info: Info, email: str) -> CreatorSchema:
"""
Query to get creator by email. Example of the GraphQL document:
```graphql
query {
getCreator(email: "[email protected]") {
Id
email
username
signedUp
assets {
type
createdAt
}
}
}
```
Args:
email (str): The email of the creator
Returns:
CreatorSchema: Data about creator and the related assets.
"""
db: AsyncIOMotorDatabase = info.context["db"]

creator = await get_creator_by_email(db, email)
if not creator:
raise GraphQLError(message="Creator does not exist.")

return CreatorSchema(**creator)

@strawberry.field
async def search_creators(
self,
info: Info,
search_text: str,
page: int = 1,
per_page: int = 10,
) -> list[CreatorSchema]:
"""
Query to search creators based on the search text. Example of the GraphQL document:
```graphql
query {
searchCreators(searchText: "New Fancy Platform", page: 1, perPage: 10) {
Id
username
email
signedUp
assets {
type
createdAt
}
}
}
```
Args:
search_text (str): The text to search for in the creators' data.
page (int): The page number of the search results.
per_page (int): The number of search results per page.
Returns:
list[CreatorSchema]: A list of creators matching the search text along with their related assets.
"""
db: AsyncIOMotorDatabase = info.context["db"]

creators = await search_creators(db, search_text, page, per_page)

return [CreatorSchema(**creator) for creator in creators]
Loading

0 comments on commit 4a24aef

Please sign in to comment.