Skip to content

Commit 5a82a90

Browse files
author
Vincent Genty
committed
Merge branch staging
2 parents dbf5e29 + cfadf76 commit 5a82a90

File tree

11 files changed

+151
-20
lines changed

11 files changed

+151
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""add_type_field_to_variables
2+
3+
Revision ID: 8deee2aef34b
4+
Revises: 2645c338180c
5+
Create Date: 2022-05-17 14:45:35.593266
6+
7+
"""
8+
from enum import Enum
9+
10+
import sqlalchemy as sa
11+
from sqlalchemy import orm
12+
from sqlalchemy.dialects.postgresql import ENUM
13+
from sqlalchemy.dialects.postgresql import UUID
14+
15+
from alembic import op
16+
17+
revision = "8deee2aef34b"
18+
down_revision = "2645c338180c"
19+
branch_labels = None
20+
depends_on = None
21+
22+
Base = orm.declarative_base()
23+
24+
25+
class VariableType(Enum):
26+
free_text = "free_text"
27+
email = "email"
28+
29+
30+
class Variable(Base): # type: ignore
31+
__tablename__ = "variables"
32+
33+
uuid = sa.Column(
34+
UUID(as_uuid=True),
35+
primary_key=True,
36+
)
37+
type = sa.Column(
38+
ENUM(VariableType),
39+
nullable=True,
40+
)
41+
42+
43+
def upgrade():
44+
variable_type = ENUM(
45+
"free_text",
46+
"email",
47+
name="variable_type",
48+
)
49+
variable_type.create(op.get_bind())
50+
51+
op.add_column(
52+
"variables",
53+
sa.Column(
54+
"type",
55+
variable_type,
56+
nullable=True,
57+
),
58+
)
59+
60+
with orm.Session(bind=op.get_bind()) as session:
61+
session.query(Variable).update({Variable.type: "free_text"})
62+
session.commit()
63+
64+
op.alter_column("variables", "type", nullable=False)
65+
66+
67+
def downgrade():
68+
op.drop_column("variables", "type")
69+
variable_type = ENUM(
70+
"free_text",
71+
"email",
72+
name="variable_type",
73+
)
74+
variable_type.drop(op.get_bind())

tests/adapters/flow_validation/helpers.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import Union
44
from uuid import UUID
55

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

5657

57-
def _string_to_uuid_or_none(value: Optional[str]) -> Optional[UUID]:
58-
return UUID(value) if value is not None else None
59-
60-
6158
def check_answer_node( # pylint: disable=too-many-locals
6259
node: Node,
6360
node_uuid: UUID,
@@ -186,7 +183,7 @@ def check_user_input_node(
186183
assert node.uuid == node_uuid
187184
user_input_data = node.data
188185
assert isinstance(user_input_data, UserInputData)
189-
assert user_input_data.variable_uuid == _string_to_uuid_or_none(
186+
assert user_input_data.variable_uuid == common.string_to_uuid_or_none(
190187
node_data_dict["variable_uuid"]
191188
)
192189
assert user_input_data.prompt_translations == node_data_dict["prompt_translations"]
@@ -207,7 +204,7 @@ def check_user_input_node(
207204
)
208205
assert (
209206
user_input_data.cancel_quick_reply_go_to_use_case_data.target_use_case_uuid
210-
== _string_to_uuid_or_none(
207+
== common.string_to_uuid_or_none(
211208
go_to_use_case_data_dict.get("target_use_case_uuid")
212209
)
213210
)
@@ -222,7 +219,7 @@ def check_create_ticket_node(node: Node, node_uuid: UUID, node_data_dict: dict)
222219
assert isinstance(create_ticket_data, CreateTicketData)
223220

224221
assert create_ticket_data.agent_channel_uuid == (
225-
_string_to_uuid_or_none(node_data_dict.get("agent_channel_uuid"))
222+
common.string_to_uuid_or_none(node_data_dict.get("agent_channel_uuid"))
226223
)
227224

228225
for actual_system_field, system_field in zip(

tests/api/namespace/test_variables.py

+15-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ def test_create_fails_if_missing_key(missing_key, client, session):
2020
assert response.status_code == 422
2121

2222

23-
@pytest.mark.parametrize("key, wrong_value", [("instance_id", "abc"), ("name", 123)])
23+
@pytest.mark.parametrize(
24+
"key, wrong_value", [("instance_id", "abc"), ("name", 123), ("type", 123)]
25+
)
2426
def test_create_fails_if_wrong_type_key(key, wrong_value, client, session):
2527
response = client.post(
2628
"/variables",
@@ -31,22 +33,29 @@ def test_create_fails_if_wrong_type_key(key, wrong_value, client, session):
3133
assert response.status_code == 422
3234

3335

34-
def test_create_variable_with_correct_parameters_work(client, session):
35-
response = client.post(
36-
"/variables", json={"instance_id": 123, "name": "My variable"}
37-
)
36+
@pytest.mark.parametrize("variable_type", [None, "email", "free_text"])
37+
def test_create_variable_with_correct_parameters_work(client, session, variable_type):
38+
payload = {"instance_id": 123, "name": "My variable"}
39+
if variable_type is not None:
40+
payload["type"] = variable_type
41+
expected_type = variable_type or "free_text"
42+
43+
response = client.post("/variables", json=payload)
3844
assert response.status_code == 200
3945
assert response.json() == {
4046
"uuid": callee.Regex(test_patterns.UUID_PATTERN),
4147
"name": "My variable",
4248
"instance_id": 123,
49+
"type": expected_type,
4350
}
4451

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

4754
assert isinstance(variable.uuid, UUID)
4855
assert variable.name == "My variable"
4956
assert variable.instance_id == 123
57+
assert variable.type == expected_type
58+
5059
now = datetime.utcnow()
5160
margin = timedelta(seconds=15)
5261
assert now - margin <= variable.created_at <= now
@@ -79,6 +88,7 @@ def test_list_variables_filters_by_instance(session, client):
7988
"uuid": callee.Regex(test_patterns.UUID_PATTERN),
8089
"name": variable.name,
8190
"instance_id": 123,
91+
"type": variable.type,
8292
}
8393
]
8494
}

tests/api/namespace/use_case/test_clone_use_case.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
)
2626
from use_case_executor.domain.flow.node_data.node_type import NodeType
2727
from use_case_executor.domain.flow.node_data.user_input_data import UserInputData
28+
from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype
2829

2930

3031
@pytest.fixture(
@@ -358,8 +359,12 @@ def test_creates_new_variables_if_cloning_to_other_instance( # pylint: disable=
358359
use_case.instance_id if clone_to_same_instance else (use_case.instance_id + 1)
359360
)
360361

361-
variable_1 = VariableFactory(instance_id=use_case.instance_id, name="variable_1")
362-
variable_2 = VariableFactory(instance_id=use_case.instance_id, name="variable_2")
362+
variable_1 = VariableFactory(
363+
instance_id=use_case.instance_id, name="variable_1", type=Variabletype.free_text
364+
)
365+
variable_2 = VariableFactory(
366+
instance_id=use_case.instance_id, name="variable_2", type=Variabletype.email
367+
)
363368
variable_3 = VariableFactory(instance_id=use_case.instance_id, name="variable_3")
364369
VariableFactory(instance_id=use_case.instance_id, name="unused_variable")
365370
VariableFactory(
@@ -525,6 +530,14 @@ def test_creates_new_variables_if_cloning_to_other_instance( # pylint: disable=
525530
.one()
526531
)
527532

533+
for variable, new_variable in zip(
534+
[variable_1, variable_2, variable_3],
535+
[new_variable_1, new_variable_2, new_variable_3],
536+
strict=True,
537+
):
538+
assert new_variable.name == variable.name
539+
assert new_variable.type == variable.type
540+
528541
new_use_case = session.query(UseCase).filter(UseCase.uuid != use_case.uuid).one()
529542
new_flow = common.dict_flow_to_domain_flow(
530543
flow=new_use_case.production_version.flow

tests/common.py

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
test_session = orm.scoped_session(orm.sessionmaker())
2222

2323

24+
def string_to_uuid_or_none(value: Optional[str]) -> Optional[UUID]:
25+
return UUID(value) if value is not None else None
26+
27+
2428
def assert_responses_call(
2529
call: Call,
2630
method: str,

tests/factories/variable_factory.py

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from tests import common
55
from use_case_executor.adapters.database_repository.models.variable import Variable
6+
from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype
67

78

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

1415
instance_id = factory.fuzzy.FuzzyInteger(1, 3)
1516
name = factory.fuzzy.FuzzyText()
17+
type = Variabletype.free_text

use_case_executor/adapters/database_repository/models/variable.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import sqlalchemy as sa
2+
from sqlalchemy.dialects.postgresql import ENUM
23
from sqlalchemy.dialects.postgresql import UUID
34
from sqlalchemy.sql.functions import func
45

56
from use_case_executor.adapters.database_repository.models.base import Base
7+
from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype
68
from use_case_executor.domain.variables.variable import Variable as DomainVariable
79

810

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

2124
def to_domain_object(self) -> DomainVariable:
2225
return DomainVariable(
2326
uuid=self.uuid,
2427
name=self.name,
2528
instance_id=self.instance_id,
29+
type=self.type,
2630
created_at=self.created_at,
2731
)

use_case_executor/api/namespaces/use_cases/clone_helpers.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ def _create_new_variables_for_flow(
9898
new_variable_uuid = uuid.uuid4()
9999
session.add(
100100
DbVariable(
101-
instance_id=instance_id, name=variable.name, uuid=new_variable_uuid
101+
instance_id=instance_id,
102+
name=variable.name,
103+
uuid=new_variable_uuid,
104+
type=variable.type,
102105
)
103106
)
104107
variable_uuid_mapping[variable.uuid] = new_variable_uuid

use_case_executor/api/namespaces/variables.py

+18-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from use_case_executor.adapters.database_repository.models.variable import Variable
99
from use_case_executor.api.database_helpers import db_session
10+
from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype
1011
from use_case_executor.monitoring import monitored_funcs
1112

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

1921

2022
class VariableModelOut(VariableModelIn):
@@ -29,10 +31,16 @@ class VariablesModelOut(BaseModel):
2931
def create_variable(variable_body: VariableModelIn) -> VariableModelOut:
3032
session = db_session.get()
3133
variable = _create_variable(
32-
session=session, name=variable_body.name, instance_id=variable_body.instance_id
34+
session=session,
35+
name=variable_body.name,
36+
instance_id=variable_body.instance_id,
37+
variable_type=variable_body.type,
3338
)
3439
return VariableModelOut(
35-
name=variable.name, instance_id=variable.instance_id, uuid=variable.uuid
40+
name=variable.name,
41+
instance_id=variable.instance_id,
42+
uuid=variable.uuid,
43+
type=variable.type,
3644
)
3745

3846

@@ -43,16 +51,21 @@ def read_variables(instance_id: int) -> VariablesModelOut:
4351
return VariablesModelOut(
4452
variables=[
4553
VariableModelOut(
46-
name=variable.name, instance_id=variable.instance_id, uuid=variable.uuid
54+
name=variable.name,
55+
instance_id=variable.instance_id,
56+
uuid=variable.uuid,
57+
type=variable.type,
4758
)
4859
for variable in variables
4960
]
5061
)
5162

5263

5364
@monitored_funcs.monitored_query("create_variable")
54-
def _create_variable(session: Session, name: str, instance_id: int) -> Variable:
55-
variable = Variable(name=name, instance_id=instance_id)
65+
def _create_variable(
66+
session: Session, name: str, instance_id: int, variable_type: Variabletype
67+
) -> Variable:
68+
variable = Variable(name=name, instance_id=instance_id, type=variable_type)
5669
session.add(variable)
5770
session.commit()
5871
return variable
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from enum import Enum
2+
3+
4+
class Variabletype(str, Enum):
5+
# The str inheritance is to specify the type of the values of the enum members
6+
# This is required for FastApi to handle enum parameters
7+
free_text = "free_text"
8+
email = "email"

use_case_executor/domain/variables/variable.py

+3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
import datetime as dt
33
from uuid import UUID
44

5+
from use_case_executor.domain.flow_execution.substeps.variable_type import Variabletype
6+
57

68
@dataclasses.dataclass(kw_only=True)
79
class Variable:
810
uuid: UUID
911
name: str
1012
instance_id: int
13+
type: Variabletype
1114
created_at: dt.datetime

0 commit comments

Comments
 (0)