Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions backend/src/baserow/contrib/database/application_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,18 +486,46 @@ def _import_field_serialized(serialized_table, serialized_field):
)
return field_instance

def _expand_implied_import_dependencies(field_deps, fields_by_name):
"""
A dependency of `(name, None)` is a reference by name to a field in the
same table. Some field types, like `link_row`, render a value borrowed
from another table, so referencing them implies a dependency on that
other field instead. Let each referenced field type say so.
"""

if not field_deps:
return field_deps

expanded = set()
for name, via in field_deps:
referenced = fields_by_name.get(name) if via is None else None
implied = referenced and field_type_registry.get(
referenced["type"]
).get_import_dependency_when_referenced(
referenced, name, database_fields_map, primary_table_fields_map
)
expanded.add(implied or (name, via))
return expanded

fields_without_dependencies: List[Field] = []
for serialized_table in serialized_tables:
table_instance = serialized_table["_object"]
serialized_fields_by_name = {
f["name"]: f for f in serialized_table["fields"]
}
for serialized_field in serialized_table["fields"]:
field_type = field_type_registry.get(serialized_field["type"])
field_deps = (
field_type.get_field_depdendencies_before_import_serialized(
serialized_field,
id_mapping["database_fields_map"],
id_mapping["primary_table_fields_map"],
database_fields_map,
primary_table_fields_map,
)
)
field_deps = _expand_implied_import_dependencies(
field_deps, serialized_fields_by_name
)

# If the field has dependencies, we want to defer the import of the
# field until all the dependencies have been imported.
Expand Down
23 changes: 23 additions & 0 deletions backend/src/baserow/contrib/database/fields/field_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3693,6 +3693,29 @@ def get_field_dependencies(
else:
return []

def get_import_dependency_when_referenced(
self,
serialized_field: Dict[str, Any],
reference_name: str,
serialized_fields_map: Dict[int, Dict[str, Any]],
primary_table_fields_map: Dict[int, int],
) -> Optional[Tuple[Union[int, str], Union[int, str]]]:
# A link row field renders the linked table's primary field, so referencing it
# by name really depends on that primary field, reached via this link row
# field. This is the import-time counterpart of `get_field_dependencies`.
related_table_id = serialized_field.get("link_row_table_id", None)

# A missing table means we're referencing a table that already exists before
# the import (i.e. duplicating a table/field), so there is nothing to order.
if related_table_id is None or related_table_id not in primary_table_fields_map:
return None

primary_field_id = primary_table_fields_map[related_table_id]
if primary_field_id not in serialized_fields_map:
return None

return (serialized_fields_map[primary_field_id]["name"], reference_name)

def should_backup_field_data_for_same_type_update(
self, old_field: LinkRowField, new_field_attrs: Dict[str, Any]
) -> bool:
Expand Down
34 changes: 34 additions & 0 deletions backend/src/baserow/contrib/database/fields/registries.py
Original file line number Diff line number Diff line change
Expand Up @@ -1593,12 +1593,46 @@ def get_field_depdendencies_before_import_serialized(
and the field name is returned.

:param serialized_field: The serialized field that is being imported.
:param serialized_fields_map: A map of all the serialized fields in the import,
keyed by their original field id.
:param primary_table_fields_map: A map of table id to the id of that table's
primary field, for all the tables in the import.
:return: A list of field name dependencies that must be imported before this
field.
"""

return None

def get_import_dependency_when_referenced(
self,
serialized_field: Dict[str, Any],
reference_name: str,
serialized_fields_map: Dict[int, Dict[str, Any]],
primary_table_fields_map: Dict[int, int],
) -> Optional[Tuple[Union[int, str], Union[int, str]]]:
"""
Returns the dependency implied by referencing this field by name from another
field in the same table, or `None` if referencing it does not imply a
dependency on anything other than the field itself.

Field types whose value is borrowed from another table, like `link_row` which
renders the linked table's primary field, must return that other field here.
Otherwise the import would order the referencing field before the field it
actually reads from.

:param serialized_field: The serialized field that is being referenced.
:param reference_name: The name the referencing field used, which is the name
of this field and therefore the `via` of any returned dependency.
:param serialized_fields_map: A map of all the serialized fields in the import,
keyed by their original field id.
:param primary_table_fields_map: A map of table id to the id of that table's
primary field, for all the tables in the import.
:return: A `(field_name, via_field_name)` dependency, or `None` when
referencing this field implies no further dependency.
"""

return None

def valid_for_bulk_update(self, field: Field) -> bool:
"""
Returns whether the field is valid for bulk updating. Fields that need to be
Expand Down
Loading
Loading