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

Release 1.0.0 #69

Merged
merged 4 commits into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion bode/bode/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from .config import Config
from .extensions import api, db, migrate
from .resources import settings, tags, task_relations, tasks
from .resources import settings, tags, task_relations, tasks, tasks_relations_flow

CONFIG = Config()

Expand Down Expand Up @@ -45,6 +45,7 @@ def register_blueprints(app):
api_blueprint.register_blueprint(tasks.api.blueprint)
api_blueprint.register_blueprint(tags.api.blueprint)
api_blueprint.register_blueprint(task_relations.api.blueprint)
api_blueprint.register_blueprint(tasks_relations_flow.api.blueprint)

app.register_blueprint(api_blueprint)
return None
74 changes: 72 additions & 2 deletions bode/bode/models/task_relation/actions.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
from types import FunctionType

from sqlalchemy import or_

from bode.app import db
from bode.models.enums import SYMMETRIC_RELATIONS, RelationType, TaskStatus
from bode.models.enums import (
SYMMETRIC_RELATIONS,
DirectedRelationType,
RelationType,
TaskStatus,
)
from bode.models.task.model import Task
from bode.models.task_relation.model import TaskRelation
from bode.utils.graph import Graph
from bode.models.utils import get_directed_relation_type
from bode.utils.graph import ExtendedRelationGraph, Graph


def create_task_relation(**relation_data):
Expand Down Expand Up @@ -114,3 +122,65 @@ def group_tasks_subsets():
.distinct(Task.id)
.all()
)


def add_untyped_graph_edge(relation: TaskRelation, graph: Graph, uuids: list()):
first_task_id, second_task_id = relation.second_task_id, relation.first_task_id
graph.add_edge(str(first_task_id), str(second_task_id))
uuids.append(str(first_task_id))
uuids.append(str(second_task_id))


def add_typed_relation_graph_edge(
relation: TaskRelation,
typed_relations_graph: ExtendedRelationGraph,
get_typed_edge: FunctionType,
get_task_DB_object: FunctionType,
):
first_task_id, second_task_id = relation.first_task_id, relation.second_task_id
directed_relation_type = get_directed_relation_type(relation, first_task_id)
task, dir_relation_type = get_typed_edge(
get_task_DB_object(first_task_id), DirectedRelationType(directed_relation_type)
)
typed_relations_graph.add_typed_edge(str(second_task_id), task, dir_relation_type)


def get_relation_flow_graph(task_id):
def get_distinct_uuids(uuids):
return list(set(uuids))

def get_relation_graph(relations):
graph = Graph()
typed_relations_graph = ExtendedRelationGraph()
get_typed_edge = typed_relations_graph.get_typed_edge
uuids = []

for relation in relations:
add_untyped_graph_edge(relation, graph, uuids)

add_typed_relation_graph_edge(relation, typed_relations_graph, get_typed_edge, get_task_DB_object)

return graph, typed_relations_graph, uuids

def group_tasks_subsets(parents):
task_parent = graph.disjoint_sets.find(task_id) if task_id in parents.keys() else task_id
tasks_subset = [key for key in parents.keys() if graph.disjoint_sets.find(key) == task_parent]
return tasks_subset

def get_task_DB_object(task_id) -> Task:
return Task.query.get(task_id)

all_tasks_relations = db.session.query(TaskRelation).all()

graph, typed_relations_graph, uuids = get_relation_graph(all_tasks_relations)
parents = graph.union_subsets(get_distinct_uuids(uuids))
all_related_tasks_set = group_tasks_subsets(parents)

res_graph = ExtendedRelationGraph()

for u in typed_relations_graph.graph:
if u in all_related_tasks_set:
for (v, relation_type) in typed_relations_graph.graph[u]:
res_graph.add_typed_edge(u, v, relation_type)

return [(get_task_DB_object(vertex), res_graph.graph[vertex]) for vertex in res_graph.graph]
1 change: 1 addition & 0 deletions bode/bode/resources/tasks_relations_flow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import api # noqa
37 changes: 37 additions & 0 deletions bode/bode/resources/tasks_relations_flow/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from uuid import UUID

from flask.views import MethodView
from flask_smorest import Blueprint

from bode.models.task_relation.actions import get_relation_flow_graph
from bode.models.task_relation.model import TaskRelation
from bode.resources.tasks_relations_flow.schemas import (
SimpleTaskRelationSchema,
TaskRelationGraphSchema,
)

blueprint = Blueprint("task-relations-flow", "task-relations-flow", url_prefix="/task-relations-flow")


@blueprint.route("")
class TasksRelations(MethodView):
@blueprint.response(200, SimpleTaskRelationSchema(many=True))
def get(self):
return TaskRelation.query.all()


@blueprint.route("/<task_id>")
class TasksFlowInRelationWith(MethodView):
@blueprint.response(200, TaskRelationGraphSchema(many=True))
def get(self, task_id: UUID):
query_result = get_relation_flow_graph(task_id)

return [
{
"task_vertex": task_vertex,
"adjacency_list": [
{"task": task, "relation_type": relation_type} for task, relation_type in adjacency_list
],
}
for task_vertex, adjacency_list in query_result
]
21 changes: 21 additions & 0 deletions bode/bode/resources/tasks_relations_flow/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from marshmallow import fields

from bode.resources.base_schema import BaseSchema
from bode.resources.tasks.schemas import TaskSchema


class SimpleTaskRelationSchema(BaseSchema):
id = fields.UUID(dump_only=True)
first_task_id = fields.UUID()
second_task_id = fields.UUID()
type = fields.String()


class TaskRelationTuplesListSchema(BaseSchema):
task = fields.Nested(TaskSchema)
relation_type = fields.String()


class TaskRelationGraphSchema(BaseSchema):
task_vertex = fields.Nested(TaskSchema)
adjacency_list = fields.List(fields.Nested(TaskRelationTuplesListSchema))
17 changes: 17 additions & 0 deletions bode/bode/utils/graph.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from collections import defaultdict
from typing import Tuple

from bode.models.enums import DirectedRelationType
from bode.models.task.model import Task


class DisjointSets:
Expand Down Expand Up @@ -47,3 +51,16 @@ def union_subsets(self, uuids):
self.disjoint_sets.union(u, v)

return self.disjoint_sets.parents


class ExtendedRelationGraph:
def __init__(self):
self.graph = defaultdict(list)

def get_typed_edge(self, v: Task, dir_relation_type: DirectedRelationType) -> Tuple[Task, DirectedRelationType]:
return (v, dir_relation_type)

def add_typed_edge(self, u: str, v: Task, relation_type: DirectedRelationType):
typed_edge = self.get_typed_edge(v, relation_type)
if typed_edge not in self.graph[u]:
self.graph[u].append(typed_edge)