import asyncio import dataclasses from dataclasses import dataclass from typing import Callable, Iterable from django.contrib.auth.models import AbstractUser from channels.testing import WebsocketCommunicator from baserow.contrib.database.fields.models import ( Field, FormulaField, LinkRowField, LookupField, ) from baserow.contrib.database.rows.handler import RowHandler from baserow.contrib.database.table.models import GeneratedTableModel, Table from baserow.contrib.database.views.handler import ViewHandler from baserow.contrib.database.views.models import GridView from baserow.test_utils.fixtures import Fixtures async def received_message(communicator: WebsocketCommunicator, message_type: str): """ Can be called to check if a specific type of message has been sent to a communicator. :param communicator: The communicator receiving the message :param message_type: The type of message you are looking for :returns: If the message has been received """ return await get_message(communicator, message_type) is not None async def get_message(communicator: WebsocketCommunicator, message_type: str): """ Can be called to find the next message of the specified type :param communicator: The communicator receiving the message :param message_type: The type of message you are looking for :return: The received message """ while True: try: message = await communicator.receive_json_from() if message["type"] == message_type: return message except asyncio.exceptions.TimeoutError: # No more messages return None @dataclass class LookupFieldSetup: user: AbstractUser table: Table other_table: Table model: GeneratedTableModel other_table_model: GeneratedTableModel grid_view: GridView link_row_field: LinkRowField lookup_field: LookupField target_field: Field row_handler: RowHandler view_handler: ViewHandler @dataclasses.dataclass class FormulaFieldSetup: user: AbstractUser table: Table formula_field: FormulaField model: GeneratedTableModel grid_view: GridView data_source_field: Field row_handler: RowHandler view_handler: ViewHandler formula: str formula_type: str extra_fields: dict[str, Field] def boolean_field_factory(data_fixture, table, user): return data_fixture.create_boolean_field(name="target", user=user, table=table) def text_field_factory(data_fixture, table, user, name: str | None = None): return data_fixture.create_text_field(name=name or "target", user=user, table=table) def long_text_field_factory(data_fixture, table, user): return data_fixture.create_long_text_field(name="target", user=user, table=table) def url_field_factory(data_fixture, table, user): return data_fixture.create_url_field(name="target", user=user, table=table) def email_field_factory(data_fixture, table, user): return data_fixture.create_email_field(name="target", user=user, table=table) def phone_number_field_factory(data_fixture, table, user): return data_fixture.create_phone_number_field(name="target", user=user, table=table) def uuid_field_factory(data_fixture, table, user): return data_fixture.create_uuid_field(name="target", user=user, table=table) def single_select_field_factory(data_fixture, table, user): return data_fixture.create_single_select_field( name="target", user=user, table=table ) def single_select_field_value_factory(data_fixture, target_field, value=None): return ( data_fixture.create_select_option(field=target_field, value=value) if value else None ) def duration_field_factory( data_fixture, table, user, duration_format: str = "d h mm", name: str | None = None ): return data_fixture.create_duration_field( name=name or "target", user=user, table=table, duration_format=duration_format ) def number_field_factory(data_fixture: Fixtures, table, user, **kwargs): return data_fixture.create_number_field( name="target", table=table, user=user, **kwargs ) def text_field_value_factory(data_fixture, target_field, value=None): return value or "" def setup_linked_table_and_lookup( data_fixture, target_field_factory, helper_fields_other_table: Iterable[Callable] = frozenset(), helper_fields_table: Iterable[Callable] = frozenset(), ) -> LookupFieldSetup: user = data_fixture.create_user() database = data_fixture.create_database_application(user=user) table = data_fixture.create_database_table(user=user, database=database) other_table = data_fixture.create_database_table(user=user, database=database) target_field = target_field_factory(data_fixture, other_table, user) for helper_field_factory in helper_fields_other_table: helper_field_factory(data_fixture, table=other_table, user=user) link_row_field = data_fixture.create_link_row_field( name="link", table=table, link_row_table=other_table ) lookup_field = data_fixture.create_lookup_field( table=table, through_field=link_row_field, target_field=target_field, through_field_name=link_row_field.name, target_field_name=target_field.name, setup_dependencies=False, ) for helper_field_factory in helper_fields_table: helper_field_factory(data_fixture, table=table, user=user) grid_view = data_fixture.create_grid_view(table=table) view_handler = ViewHandler() row_handler = RowHandler() model = table.get_model() other_table_model = other_table.get_model() return LookupFieldSetup( user=user, table=table, other_table=other_table, other_table_model=other_table_model, target_field=target_field, row_handler=row_handler, grid_view=grid_view, link_row_field=link_row_field, lookup_field=lookup_field, view_handler=view_handler, model=model, ) def setup_formula_field( data_fixture, formula_text: str, formula_type: str, data_field_factory, extra_fields: Iterable[Callable], formula_extra_kwargs: dict | None = None, ) -> FormulaFieldSetup: """ Create a table with duration formula field. :param data_fixture: :param formula_text: :param formula_type: :param data_field_factory: :param extra_fields: iterable with field factory functions. :param formula_extra_kwargs: optional dict with additional keyword args for formula field creation :return: """ user = data_fixture.create_user() database = data_fixture.create_database_application(user=user) table = data_fixture.create_database_table(user=user, database=database) data_source_field = data_field_factory(data_fixture, table, user) formula_field = data_fixture.create_formula_field( table=table, user=user, formula=formula_text, formula_type=formula_type, **{k: v for k, v in (formula_extra_kwargs or {}).items()}, ) extra_fields_map = {} for field_factory in extra_fields: extra_field = field_factory(data_fixture, table=table, user=user) extra_fields_map[extra_field.name] = extra_field grid_view = data_fixture.create_grid_view(table=table) view_handler = ViewHandler() row_handler = RowHandler() model = table.get_model() return FormulaFieldSetup( user=user, table=table, data_source_field=data_source_field, formula_field=formula_field, row_handler=row_handler, grid_view=grid_view, view_handler=view_handler, model=model, formula=formula_text, formula_type=formula_type, extra_fields=extra_fields_map, )