Skip to content

Commit

Permalink
Merge branch staging
Browse files Browse the repository at this point in the history
  • Loading branch information
Vincent Genty committed May 18, 2022
2 parents dbf5e29 + cfadf76 commit 5a82a90
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 20 deletions.
74 changes: 74 additions & 0 deletions alembic/versions/2022-05-17_add_type_field_to_variables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""add_type_field_to_variables
Revision ID: 8deee2aef34b
Revises: 2645c338180c
Create Date: 2022-05-17 14:45:35.593266
"""
from enum import Enum

import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.dialects.postgresql import ENUM
from sqlalchemy.dialects.postgresql import UUID

from alembic import op

revision = "8deee2aef34b"
down_revision = "2645c338180c"
branch_labels = None
depends_on = None

Base = orm.declarative_base()


class VariableType(Enum):
free_text = "free_text"
email = "email"


class Variable(Base): # type: ignore
__tablename__ = "variables"

uuid = sa.Column(
UUID(as_uuid=True),
primary_key=True,
)
type = sa.Column(
ENUM(VariableType),
nullable=True,
)


def upgrade():
variable_type = ENUM(
"free_text",
"email",
name="variable_type",
)
variable_type.create(op.get_bind())

op.add_column(
"variables",
sa.Column(
"type",
variable_type,
nullable=True,
),
)

with orm.Session(bind=op.get_bind()) as session:
session.query(Variable).update({Variable.type: "free_text"})
session.commit()

op.alter_column("variables", "type", nullable=False)


def downgrade():
op.drop_column("variables", "type")
variable_type = ENUM(
"free_text",
"email",
name="variable_type",
)
variable_type.drop(op.get_bind())
11 changes: 4 additions & 7 deletions tests/adapters/flow_validation/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Union
from uuid import UUID

from tests import common
from tests.fixtures.valid_flow_json import * # noqa: F401, F403, pylint: disable=wildcard-import,unused-wildcard-import
from use_case_executor.adapters.flow_validation.edge import Edge
from use_case_executor.adapters.flow_validation.edge_data.direct_link_data import (
Expand Down Expand Up @@ -54,10 +55,6 @@
from use_case_executor.domain.flow.node_data.node_type import NodeType


def _string_to_uuid_or_none(value: Optional[str]) -> Optional[UUID]:
return UUID(value) if value is not None else None


def check_answer_node( # pylint: disable=too-many-locals
node: Node,
node_uuid: UUID,
Expand Down Expand Up @@ -186,7 +183,7 @@ def check_user_input_node(
assert node.uuid == node_uuid
user_input_data = node.data
assert isinstance(user_input_data, UserInputData)
assert user_input_data.variable_uuid == _string_to_uuid_or_none(
assert user_input_data.variable_uuid == common.string_to_uuid_or_none(
node_data_dict["variable_uuid"]
)
assert user_input_data.prompt_translations == node_data_dict["prompt_translations"]
Expand All @@ -207,7 +204,7 @@ def check_user_input_node(
)
assert (
user_input_data.cancel_quick_reply_go_to_use_case_data.target_use_case_uuid
== _string_to_uuid_or_none(
== common.string_to_uuid_or_none(
go_to_use_case_data_dict.get("target_use_case_uuid")
)
)
Expand All @@ -222,7 +219,7 @@ def check_create_ticket_node(node: Node, node_uuid: UUID, node_data_dict: dict)
assert isinstance(create_ticket_data, CreateTicketData)

assert create_ticket_data.agent_channel_uuid == (
_string_to_uuid_or_none(node_data_dict.get("agent_channel_uuid"))
common.string_to_uuid_or_none(node_data_dict.get("agent_channel_uuid"))
)

for actual_system_field, system_field in zip(
Expand Down
20 changes: 15 additions & 5 deletions tests/api/namespace/test_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ def test_create_fails_if_missing_key(missing_key, client, session):
assert response.status_code == 422


@pytest.mark.parametrize("key, wrong_value", [("instance_id", "abc"), ("name", 123)])
@pytest.mark.parametrize(
"key, wrong_value", [("instance_id", "abc"), ("name", 123), ("type", 123)]
)
def test_create_fails_if_wrong_type_key(key, wrong_value, client, session):
response = client.post(
"/variables",
Expand All @@ -31,22 +33,29 @@ def test_create_fails_if_wrong_type_key(key, wrong_value, client, session):
assert response.status_code == 422


def test_create_variable_with_correct_parameters_work(client, session):
response = client.post(
"/variables", json={"instance_id": 123, "name": "My variable"}
)
@pytest.mark.parametrize("variable_type", [None, "email", "free_text"])
def test_create_variable_with_correct_parameters_work(client, session, variable_type):
payload = {"instance_id": 123, "name": "My variable"}
if variable_type is not None:
payload["type"] = variable_type
expected_type = variable_type or "free_text"

response = client.post("/variables", json=payload)
assert response.status_code == 200
assert response.json() == {
"uuid": callee.Regex(test_patterns.UUID_PATTERN),
"name": "My variable",
"instance_id": 123,
"type": expected_type,
}

variable = session.query(Variable).one()

assert isinstance(variable.uuid, UUID)
assert variable.name == "My variable"
assert variable.instance_id == 123
assert variable.type == expected_type

now = datetime.utcnow()
margin = timedelta(seconds=15)
assert now - margin <= variable.created_at <= now
Expand Down Expand Up @@ -79,6 +88,7 @@ def test_list_variables_filters_by_instance(session, client):
"uuid": callee.Regex(test_patterns.UUID_PATTERN),
"name": variable.name,
"instance_id": 123,
"type": variable.type,
}
]
}
17 changes: 15 additions & 2 deletions tests/api/namespace/use_case/test_clone_use_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
)
from use_case_executor.domain.flow.node_data.node_type import NodeType
from use_case_executor.domain.flow.node_data.user_input_data import UserInputData
from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype


@pytest.fixture(
Expand Down Expand Up @@ -358,8 +359,12 @@ def test_creates_new_variables_if_cloning_to_other_instance( # pylint: disable=
use_case.instance_id if clone_to_same_instance else (use_case.instance_id + 1)
)

variable_1 = VariableFactory(instance_id=use_case.instance_id, name="variable_1")
variable_2 = VariableFactory(instance_id=use_case.instance_id, name="variable_2")
variable_1 = VariableFactory(
instance_id=use_case.instance_id, name="variable_1", type=Variabletype.free_text
)
variable_2 = VariableFactory(
instance_id=use_case.instance_id, name="variable_2", type=Variabletype.email
)
variable_3 = VariableFactory(instance_id=use_case.instance_id, name="variable_3")
VariableFactory(instance_id=use_case.instance_id, name="unused_variable")
VariableFactory(
Expand Down Expand Up @@ -525,6 +530,14 @@ def test_creates_new_variables_if_cloning_to_other_instance( # pylint: disable=
.one()
)

for variable, new_variable in zip(
[variable_1, variable_2, variable_3],
[new_variable_1, new_variable_2, new_variable_3],
strict=True,
):
assert new_variable.name == variable.name
assert new_variable.type == variable.type

new_use_case = session.query(UseCase).filter(UseCase.uuid != use_case.uuid).one()
new_flow = common.dict_flow_to_domain_flow(
flow=new_use_case.production_version.flow
Expand Down
4 changes: 4 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
test_session = orm.scoped_session(orm.sessionmaker())


def string_to_uuid_or_none(value: Optional[str]) -> Optional[UUID]:
return UUID(value) if value is not None else None


def assert_responses_call(
call: Call,
method: str,
Expand Down
2 changes: 2 additions & 0 deletions tests/factories/variable_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from tests import common
from use_case_executor.adapters.database_repository.models.variable import Variable
from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype


class VariableFactory(alchemy.SQLAlchemyModelFactory):
Expand All @@ -13,3 +14,4 @@ class Meta:

instance_id = factory.fuzzy.FuzzyInteger(1, 3)
name = factory.fuzzy.FuzzyText()
type = Variabletype.free_text
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import ENUM
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.sql.functions import func

from use_case_executor.adapters.database_repository.models.base import Base
from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype
from use_case_executor.domain.variables.variable import Variable as DomainVariable


Expand All @@ -17,11 +19,13 @@ class Variable(Base):
created_at = sa.Column(sa.DateTime, nullable=False, server_default=func.now())
name = sa.Column(sa.String, nullable=False)
instance_id = sa.Column(sa.Integer, nullable=False)
type = sa.Column(ENUM(Variabletype), nullable=False)

def to_domain_object(self) -> DomainVariable:
return DomainVariable(
uuid=self.uuid,
name=self.name,
instance_id=self.instance_id,
type=self.type,
created_at=self.created_at,
)
5 changes: 4 additions & 1 deletion use_case_executor/api/namespaces/use_cases/clone_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ def _create_new_variables_for_flow(
new_variable_uuid = uuid.uuid4()
session.add(
DbVariable(
instance_id=instance_id, name=variable.name, uuid=new_variable_uuid
instance_id=instance_id,
name=variable.name,
uuid=new_variable_uuid,
type=variable.type,
)
)
variable_uuid_mapping[variable.uuid] = new_variable_uuid
Expand Down
23 changes: 18 additions & 5 deletions use_case_executor/api/namespaces/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from use_case_executor.adapters.database_repository.models.variable import Variable
from use_case_executor.api.database_helpers import db_session
from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype
from use_case_executor.monitoring import monitored_funcs

router = APIRouter(prefix="/variables", tags=["variables"])
Expand All @@ -15,6 +16,7 @@
class VariableModelIn(BaseModel):
name: StrictStr
instance_id: StrictInt
type: Variabletype = Variabletype.free_text


class VariableModelOut(VariableModelIn):
Expand All @@ -29,10 +31,16 @@ class VariablesModelOut(BaseModel):
def create_variable(variable_body: VariableModelIn) -> VariableModelOut:
session = db_session.get()
variable = _create_variable(
session=session, name=variable_body.name, instance_id=variable_body.instance_id
session=session,
name=variable_body.name,
instance_id=variable_body.instance_id,
variable_type=variable_body.type,
)
return VariableModelOut(
name=variable.name, instance_id=variable.instance_id, uuid=variable.uuid
name=variable.name,
instance_id=variable.instance_id,
uuid=variable.uuid,
type=variable.type,
)


Expand All @@ -43,16 +51,21 @@ def read_variables(instance_id: int) -> VariablesModelOut:
return VariablesModelOut(
variables=[
VariableModelOut(
name=variable.name, instance_id=variable.instance_id, uuid=variable.uuid
name=variable.name,
instance_id=variable.instance_id,
uuid=variable.uuid,
type=variable.type,
)
for variable in variables
]
)


@monitored_funcs.monitored_query("create_variable")
def _create_variable(session: Session, name: str, instance_id: int) -> Variable:
variable = Variable(name=name, instance_id=instance_id)
def _create_variable(
session: Session, name: str, instance_id: int, variable_type: Variabletype
) -> Variable:
variable = Variable(name=name, instance_id=instance_id, type=variable_type)
session.add(variable)
session.commit()
return variable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from enum import Enum


class Variabletype(str, Enum):
# The str inheritance is to specify the type of the values of the enum members
# This is required for FastApi to handle enum parameters
free_text = "free_text"
email = "email"
3 changes: 3 additions & 0 deletions use_case_executor/domain/variables/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
import datetime as dt
from uuid import UUID

from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype


@dataclasses.dataclass(kw_only=True)
class Variable:
uuid: UUID
name: str
instance_id: int
type: Variabletype
created_at: dt.datetime

0 comments on commit 5a82a90

Please sign in to comment.