diff --git a/bd_api/apps/api/v1/models.py b/bd_api/apps/api/v1/models.py index 569cfda8..2dcdd8d1 100644 --- a/bd_api/apps/api/v1/models.py +++ b/bd_api/apps/api/v1/models.py @@ -217,6 +217,24 @@ def coverage_type(self): coverage_type.short_description = "Coverage Type" + def has_area_intersection(self, other: "Coverage"): + if not self.area: + return True + if not other.area: + return True + if self.area.name.startswith(other.area.name): + return True + if other.area.name.startswith(self.area.name): + return True + return False + + def has_datetime_intersection(self, other: "Coverage"): + for dt_self in self.datetime_ranges.all(): + for dt_other in other.datetime_ranges.all(): + if dt_self.has_datetime_intersection(dt_other): + return True + return False + def clean(self) -> None: """ Assert that only one of "table", "raw_data_source", @@ -893,10 +911,8 @@ def clean(self) -> None: "One and only one of 'table', " "'raw_data_source', or 'information_request' must be set." ) - if self.entity.category.slug != "datetime": raise ValidationError("Entity's category is not in category.slug = `datetime`.") - return super().clean() @@ -1122,7 +1138,7 @@ def get_graphql_full_coverage(self): def neighbors(self): """Similiar tables and columns - Tables and columns with similar directories - - Tables and columns with similar coverages or tags (WIP) + - Tables and columns with similar coverages or tags """ all_neighbors = [] for column in self.columns.all(): @@ -1153,6 +1169,27 @@ def last_updated_at(self): def get_graphql_last_updated_at(self): return self.last_updated_at + def has_area_intersection(self, other: "Table"): + for cov_self in self.coverages.all(): + for cov_other in other.coverages.all(): + if cov_self.has_area_intersection(cov_other): + return True + return False + + def has_datetime_intersection(self, other: "Table"): + for cov_self in self.coverages.all(): + for cov_other in other.coverages.all(): + if cov_self.has_datetime_intersection(cov_other): + return True + return False + + def has_directory_intersection(self, other: "Table"): + for col_self in self.columns.all(): + for col_other in other.columns.all(): + if col_self.has_directory_intersection(col_other): + return True + return False + def clean(self): """ Clean method for Table model @@ -1275,24 +1312,6 @@ class Meta: verbose_name_plural = "Columns" ordering = ["name"] - def clean(self) -> None: - """Clean method for Column model""" - errors = {} - if self.observation_level and self.observation_level.table != self.table: - errors[ - "observation_level" - ] = "Observation level is not in the same table as the column." - - if self.directory_primary_key and self.directory_primary_key.table.is_directory is False: - errors[ - "directory_primary_key" - ] = "Column indicated as a directory's primary key is not in a directory." - - if errors: - raise ValidationError(errors) - - return super().clean() - @property def full_coverage(self) -> str: """ @@ -1349,7 +1368,7 @@ def get_graphql_full_coverage(self): def neighbors(self): """Similiar tables and columns - Columns with similar directories - - Columns with similar coverages or tags (WIP) + - Columns with similar coverages or tags """ if not self.directory_primary_key: return [] @@ -1384,6 +1403,26 @@ def get_graphql_neighbors(self) -> list[dict]: ) return get_unique_list(all_neighbors) + def has_directory_intersection(self, other: "Column"): + if self.directory_primary_key == other.directory_primary_key: + return True + return False + + def clean(self) -> None: + """Clean method for Column model""" + errors = {} + if self.observation_level and self.observation_level.table != self.table: + errors[ + "observation_level" + ] = "Observation level is not in the same table as the column." + if self.directory_primary_key and self.directory_primary_key.table.is_directory is False: + errors[ + "directory_primary_key" + ] = "Column indicated as a directory's primary key is not in a directory." + if errors: + raise ValidationError(errors) + return super().clean() + class ColumnOriginalName(BaseModel): """Model definition for ColumnOriginalName.""" @@ -1806,6 +1845,39 @@ class Meta: verbose_name_plural = "DateTime Ranges" ordering = ["id"] + @property + def since(self): + if self.start_year: + return datetime( + self.start_year, + self.start_month or 1, + self.start_day or 1, + self.start_hour or 0, + self.start_minute or 0, + self.start_second or 0, + ) + + @property + def until(self): + if self.end_year: + return datetime( + self.end_year, + self.end_month or 1, + self.end_day or 1, + self.end_hour or 0, + self.end_minute or 0, + self.end_second or 0, + ) + + def has_datetime_intersection(self, other: "DateTimeRange"): + if not self.since: + return True + if not other.until: + return True + if self.until >= other.since: + return True + return False + def clean(self) -> None: """ Assert that start_year <= end_year and start_month <= end_month