diff --git a/pyproject.toml b/pyproject.toml index 2f1b486..9c73871 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "welearn-database" -version = "1.3.0" +version = "1.4.0.dev0" description = "All stuff related to relationnal database from the WeLearn project" authors = [ {name = "Théo",email = "theo.nardin@cri-paris.org"} diff --git a/tests/test_user_related.py b/tests/test_user_related.py index 4c911c9..1a02eee 100644 --- a/tests/test_user_related.py +++ b/tests/test_user_related.py @@ -6,6 +6,7 @@ from sqlalchemy.orm import sessionmaker from tests.helpers import handle_schema_with_sqlite +from welearn_database.data.enumeration import FilterType from welearn_database.data.models import Base from welearn_database.data.models.user_related import ( APIKeyManagement, @@ -13,6 +14,7 @@ ChatMessage, DataCollectionCampaignManagement, EndpointRequest, + FilterUsedInQuery, InferredUser, ReturnedDocument, ) @@ -114,12 +116,14 @@ def test_create_and_read_chat_message(self): conversation_id=uuid.uuid4(), role="user", textual_content="Bonjour", + original_feature_name="chat", ) self.session.add(chat) self.session.commit() result = self.session.query(ChatMessage).filter_by(role="user").first() self.assertIsNotNone(result) self.assertEqual(result.textual_content, "Bonjour") + self.assertFalse(result.is_retrieved_by_user) def test_create_and_read_bookmark(self): inferred_user = InferredUser(id=uuid.uuid4()) @@ -149,6 +153,7 @@ def test_create_and_read_returned_document(self): inferred_user_id=inferred_user.id, conversation_id=uuid.uuid4(), role="user", + original_feature_name="chat", textual_content="test", ) self.session.add(chat) @@ -193,3 +198,30 @@ def test_create_and_read_endpoint_request(self): ) self.assertIsNotNone(result) self.assertEqual(result.http_code, 200) + + def test_create_and_read_filter_used_in_query(self): + inferred_user = InferredUser(id=uuid.uuid4()) + self.session.add(inferred_user) + self.session.commit() + chat = ChatMessage( + id=uuid.uuid4(), + inferred_user_id=inferred_user.id, + conversation_id=uuid.uuid4(), + role="user", + original_feature_name="chat", + textual_content="test", + ) + self.session.add(chat) + self.session.commit() + filter_used = FilterUsedInQuery( + id=uuid.uuid4(), + message_id=chat.id, + filter_type=FilterType.SDG.value, + filter_value="13", + ) + self.session.add(filter_used) + self.session.commit() + result = ( + self.session.query(FilterUsedInQuery).filter_by(filter_value="13").first() + ) + self.assertIsNotNone(result) diff --git a/welearn_database/alembic/versions/9b4f1da0c1f2_data_collection_for_focus_group.py b/welearn_database/alembic/versions/9b4f1da0c1f2_data_collection_for_focus_group.py new file mode 100644 index 0000000..e0bcf07 --- /dev/null +++ b/welearn_database/alembic/versions/9b4f1da0c1f2_data_collection_for_focus_group.py @@ -0,0 +1,76 @@ +"""data collection for focus group + +Revision ID: 9b4f1da0c1f2 +Revises: 2ad4895b2674 +Create Date: 2026-02-23 18:11:55.857517 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = "9b4f1da0c1f2" +down_revision: Union[str, None] = "2ad4895b2674" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.add_column( + "chat_message", + sa.Column( + "is_retrieved_by_user", + sa.Boolean(), + nullable=False, + default=False, + server_default="False", + ), + schema="user_related", + ) + op.add_column( + "chat_message", + sa.Column("original_feature_name", sa.String(), nullable=True), + schema="user_related", + ) + op.create_table( + "filter_used_in_query", + sa.Column( + "id", sa.Uuid(), server_default=sa.func.gen_random_uuid(), nullable=False + ), + sa.Column("message_id", sa.Uuid(), nullable=False), + sa.Column( + "filter_type", + postgresql.ENUM( + "sdg", + "source", + name="filter_type", + schema="user_related", + ), + nullable=False, + ), + sa.Column("filter_value", sa.String(), nullable=False), + sa.ForeignKeyConstraint( + ["message_id"], + ["user_related.chat_message.id"], + name="filter_used_in_query_message_id_fkey", + ), + sa.PrimaryKeyConstraint("id"), + schema="user_related", + ) + + +def downgrade() -> None: + op.drop_column("chat_message", "is_retrieved_by_user", schema="user_related") + op.drop_column("chat_message", "original_feature_name", schema="user_related") + op.drop_constraint( + "filter_used_in_query_message_id_fkey", + "filter_used_in_query", + schema="user_related", + type_="foreignkey", + ) + op.drop_table("filter_used_in_query", schema="user_related") + op.execute("DROP TYPE IF EXISTS user_related.filter_type") diff --git a/welearn_database/data/enumeration.py b/welearn_database/data/enumeration.py index c64f07e..99b78e1 100644 --- a/welearn_database/data/enumeration.py +++ b/welearn_database/data/enumeration.py @@ -38,3 +38,8 @@ class ExternalIdType(StrEnum): HANDLE = auto() SLUG = auto() QID = auto() + + +class FilterType(StrEnum): + SDG = auto() + SOURCE = auto() diff --git a/welearn_database/data/models/user_related.py b/welearn_database/data/models/user_related.py index 9c3af47..149a407 100644 --- a/welearn_database/data/models/user_related.py +++ b/welearn_database/data/models/user_related.py @@ -2,10 +2,10 @@ from uuid import UUID from sqlalchemy import ForeignKey, func, types -from sqlalchemy.dialects.postgresql import TIMESTAMP +from sqlalchemy.dialects.postgresql import ENUM, TIMESTAMP from sqlalchemy.orm import Mapped, mapped_column, relationship -from welearn_database.data.enumeration import DbSchemaEnum +from welearn_database.data.enumeration import DbSchemaEnum, FilterType from welearn_database.data.models.document_related import WeLearnDocument from . import Base @@ -96,6 +96,10 @@ class ChatMessage(Base): ) role: Mapped[str] textual_content: Mapped[str] + is_retrieved_by_user: Mapped[bool] = mapped_column( + default=False, server_default="False" + ) + original_feature_name: Mapped[str | None] created_at: Mapped[datetime] = mapped_column( TIMESTAMP(timezone=False), @@ -134,6 +138,7 @@ class ReturnedDocument(Base): nullable=False, ) is_clicked: Mapped[bool] = mapped_column(default=False) + welearn_document: Mapped["WeLearnDocument"] = relationship() chat_message: Mapped["ChatMessage"] = relationship() @@ -240,3 +245,27 @@ class EndpointRequest(Base): server_default="NOW()", ) session = relationship("Session", foreign_keys=[session_id]) + + +class FilterUsedInQuery(Base): + __tablename__ = "filter_used_in_query" + __table_args__ = {"schema": DbSchemaEnum.USER_RELATED.value} + + id: Mapped[UUID] = mapped_column( + types.Uuid, primary_key=True, nullable=False, server_default="gen_random_uuid()" + ) + message_id = mapped_column( + types.Uuid, + ForeignKey(f"{DbSchemaEnum.USER_RELATED.value}.chat_message.id"), + nullable=False, + ) + filter_type: Mapped[str] = mapped_column( + ENUM( + *(e.value.lower() for e in FilterType), + name="filter_type", + schema=DbSchemaEnum.USER_RELATED.value, + ), + ) + filter_value: Mapped[str] + + chat_message: Mapped["ChatMessage"] = relationship()