Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL schema for exercises aggregated by week #27

Merged
merged 11 commits into from
Mar 29, 2024
21 changes: 18 additions & 3 deletions analytics/core/gql_schema.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from ariadne import gql, make_executable_schema, QueryType
from core.models import mongo
from core.query import stats_query, stats_by_username_query

from core.query import stats_query, stats_by_username_query, stats_by_week_start_end_dates_query

type_defs = gql("""
type Query {
stats: [Stats]
statsByUsername(username: String): [Stats]
statsAggregatedByWeek(username:String, startdate: String, enddate: String): [Exercise]
}

type Stats {
Expand All @@ -17,7 +17,7 @@
type Exercise {
exerciseType: ExerciseType!
totalDuration: Int!
totalDistance: Int
totalDistance: Float
averagePace: Float
averageSpeed: Float
topSpeed: Float
Expand All @@ -30,10 +30,12 @@
Gym
Other
}

""")

query = QueryType()


@query.field("stats")
def stats_resolver(*_):
pipeline = stats_query()
Expand All @@ -49,4 +51,17 @@ def stats_by_username_resolver(*_, username=None):
stats = list(mongo.db.exercises.aggregate(pipeline))
return stats


@query.field("statsAggregatedByWeek")
def stats_by_week_start_end_dates_resolver(*_, username=None, startdate=None, enddate=None):
pipeline = stats_by_week_start_end_dates_query(
username=username,
start_date=startdate,
end_date=enddate
)

stats = list(mongo.db.exercises.aggregate(pipeline))
return stats


schema = make_executable_schema(type_defs, query)
46 changes: 46 additions & 0 deletions analytics/core/query.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from datetime import datetime, timedelta


def stats_query():
return [
{
Expand Down Expand Up @@ -79,3 +82,46 @@ def stats_by_username_query(username):
}
}
]


def stats_by_week_start_end_dates_query(username, start_date, end_date):
# format the string dates to a form accepted by mongodb
date_format = "%Y-%m-%d"
start_date = datetime.strptime(start_date, date_format)
# Include the whole end day
end_date = datetime.strptime(end_date, date_format) + timedelta(days=1)

return [
{
"$match": {
"username": username,
"date": {
"$gte": start_date,
"$lt": end_date
}
}
},
{
"$group": {
"_id": {
"exerciseType": "$exerciseType"
},
"totalDuration": {"$sum": "$duration"},
"totalDistance": {"$sum": "$distance"},
"averagePace": {"$avg": "$pace"},
"averageSpeed": {"$avg": "$speed"},
"topSpeed": {"$max": "$speed"}
}
},
{
"$project": {
"exerciseType": "$_id.exerciseType",
"totalDuration": 1,
"totalDistance": 1,
"averagePace": 1,
"averageSpeed": 1,
"topSpeed": 1,
"_id": 0
}
}
]
74 changes: 16 additions & 58 deletions analytics/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,83 +10,43 @@
from ariadne.explorer import ExplorerGraphiQL
from ariadne import graphql_sync

from core.query import stats_query, stats_by_username_query
from core.query import stats_query, stats_by_username_query, stats_by_week_start_end_dates_query

stats_page = Blueprint('stats_page', __name__)


@stats_page.route('/')
def index():
exercises = mongo.db.exercises.find()
exercises_list = list(exercises)
return json_util.dumps(exercises_list)


@stats_page.route('/stats')
def stats():
pipeline = stats_query()

stats = list(mongo.db.exercises.aggregate(pipeline))
return jsonify(stats=stats)


@stats_page.route('/stats/<username>', methods=['GET'])
def user_stats(username):
pipeline = stats_by_username_query(username=username)

stats = list(mongo.db.exercises.aggregate(pipeline))
return jsonify(stats=stats)


@stats_page.route('/stats/weekly/', methods=['GET'])
def weekly_user_stats():
username = request.args.get('user')
start_date_str = request.args.get('start')
end_date_str = request.args.get('end')

date_format = "%Y-%m-%d"
try:
start_date = datetime.strptime(start_date_str, date_format)
# Include the whole end day
end_date = datetime.strptime(
end_date_str, date_format) + timedelta(days=1)
start_date = request.args.get('start')
end_date = request.args.get('end')

logging.info(
f"Fetching weekly stats for user: {username} from {start_date} to {end_date}")
except Exception as e:
logging.error(f"Error parsing dates: {e}")
return jsonify(error="Invalid date format"), 400

pipeline = [
{
"$match": {
"username": username,
"date": {
"$gte": start_date,
"$lt": end_date
}
}
},
{
"$group": {
"_id": {
"exerciseType": "$exerciseType"
},
"totalDuration": {"$sum": "$duration"},
"totalDistance": {"$sum": "$distance"},
"averagePace": {"$avg": "$pace"},
"averageSpeed": {"$avg": "$speed"},
"topSpeed": {"$max": "$speed"}
}
},
{
"$project": {
"exerciseType": "$_id.exerciseType",
"totalDuration": 1,
"totalDistance": 1,
"averagePace": 1,
"averageSpeed": 1,
"topSpeed": 1,
"_id": 0
}
}
]
pipeline = stats_by_week_start_end_dates_query(
username, start_date, end_date
)

try:
stats = list(mongo.db.exercises.aggregate(pipeline))
Expand All @@ -97,23 +57,21 @@ def weekly_user_stats():
traceback.print_exc()
return jsonify(error="An internal error occurred"), 500


explorer_html = ExplorerGraphiQL().html(None)


@stats_page.route('/stats/graphql', methods=["GET"])
def graphql_explorer():
return explorer_html, 200


@stats_page.route("/stats/graphql", methods=["POST"])
def graphql_server():
data = request.get_json()
success, result = graphql_sync(
schema, data, context_value={"request": request}, debug=app.debug
)
app.logger.info('%s data returned:', result)
if success:
data = result['data']
status_code = 200
else:
data = result
status_code = 400
return jsonify(data), status_code
app.logger.info(f'data returned: {result}')
status_code = 200 if success else 400
return jsonify(result), status_code
Loading
Loading