Skip to content

Commit

Permalink
feat: turn python properties into graphql attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
vncsna committed Feb 20, 2024
1 parent 5d6ae51 commit 8b07e26
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 133 deletions.
12 changes: 8 additions & 4 deletions bd_api/apps/account/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,28 +349,32 @@ def get_organization(self):

get_organization.short_description = "organização"

def get_graphql_pro_subscription(self) -> str:
@property
def pro_subscription(self) -> str:
"""BD Pro subscription role, one of bd_pro or bd_pro_empresas"""
if self.pro_owner_subscription:
return self.pro_owner_subscription.stripe_subscription
if self.pro_member_subscription:
return self.pro_member_subscription.stripe_subscription

def get_graphql_pro_subscription_role(self) -> str:
@property
def pro_subscription_role(self) -> str:
"""BD Pro subscription role, one of owner or member"""
if self.pro_owner_subscription:
return "owner"
if self.pro_member_subscription:
return "member"

def get_graphql_pro_subscription_slots(self) -> str:
@property
def pro_subscription_slots(self) -> str:
"""BD Pro subscription slots"""
if self.pro_owner_subscription:
return self.pro_owner_subscription.stripe_subscription_slots
if self.pro_member_subscription:
return self.pro_member_subscription.stripe_subscription_slots

def get_graphql_pro_subscription_status(self) -> str:
@property
def pro_subscription_status(self) -> str:
"""BD Pro subscription status"""
if self.pro_owner_subscription:
return self.pro_owner_subscription.stripe_subscription_status
Expand Down
147 changes: 31 additions & 116 deletions bd_api/apps/api/v1/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,32 +453,17 @@ class Meta:
verbose_name_plural = "Organizations"
ordering = ["slug"]

def has_picture(self):
"""Check if the organization has a picture"""
try:
hasattr(self.picture, "url")
except Exception:
return False
return self.picture is not None

has_picture.short_description = "Has Picture"
has_picture.boolean = True

def get_graphql_has_picture(self):
"""Get the has_picture property for graphql"""
return self.has_picture()

@property
def full_slug(self):
"""Get the full slug or Organization"""
if self.area.slug != "unknown":
return f"{self.area.slug}_{self.slug}"

return f"{self.slug}"

def get_graphql_full_slug(self):
"""Get the full slug or Organization for graphql"""
return self.full_slug
@property
def has_picture(self):
if self.picture and self.picture.url:
return True
return False


class Status(BaseModel):
Expand Down Expand Up @@ -567,10 +552,6 @@ def full_slug(self):
return f"{self.organization.area.slug}_{self.organization.slug}_{self.slug}"
return f"{self.organization.slug}_{self.slug}"

def get_graphql_full_slug(self):
"""Get the full slug or Dataset for graphql"""
return self.full_slug

@property
def coverage(self):
"""Get the temporal coverage of the dataset in the format YYYY-MM-DD - YYYY-MM-DD"""
Expand Down Expand Up @@ -690,13 +671,6 @@ def coverage(self):

return coverage_str

def get_graphql_coverage(self):
"""
Returns the temporal coverage of the dataset in the format
YYYY-MM-DD - YYYY-MM-DD for graphql
"""
return self.coverage

@property
def full_coverage(self) -> str:
"""
Expand All @@ -718,18 +692,11 @@ def full_coverage(self) -> str:
]
return json.dumps(full_coverage_dict)

def get_graphql_full_coverage(self):
return self.full_coverage

@property
def contains_tables(self):
"""Returns true if there are tables in the dataset"""
return len(self.tables.all()) > 0

def get_graphql_contains_tables(self):
"""Returns true if there are tables in the dataset for graphql"""
return self.contains_tables

@property
def contains_closed_data(self):
"""Returns true if there are tables or columns with closed coverages"""
Expand All @@ -747,10 +714,6 @@ def contains_closed_data(self):

return closed_data

def get_graphql_contains_closed_data(self):
"""Returns true if there are tables or columns with closed coverages for graphql"""
return self.contains_closed_data

@property
def contains_open_data(self):
"""Returns true if there are tables or columns with open coverages"""
Expand All @@ -764,48 +727,28 @@ def contains_open_data(self):

return open_data

def get_graphql_contains_open_data(self):
"""Returns true if there are tables or columns with open coverages for graphql"""
return self.contains_open_data

@property
def contains_closed_tables(self):
"""Returns true if there are tables with closed coverages (DEPRECATED)"""
closed_tables = self.tables.all().filter(is_closed=True)
return len(closed_tables) > 0

def get_graphql_contains_closed_tables(self):
"""Returns true if there are tables with closed coverages for graphql (DEPRECATED)"""
return self.contains_closed_tables

@property
def contains_open_tables(self):
"""Returns true if there are tables with open coverages (DEPRECATED)"""
open_tables = self.tables.all().filter(is_closed=False)
return len(open_tables) > 0

def get_graphql_contains_open_tables(self):
"""Returns true if there are tables with open coverages for graphql (DEPRECATED)"""
return self.contains_open_tables

@property
def contains_raw_data_sources(self):
"""Returns true if there are raw data sources in the dataset"""
return len(self.raw_data_sources.all()) > 0

def get_graphql_contains_raw_data_sources(self):
"""Returns true if there are raw data sources in the dataset for graphql"""
return self.contains_raw_data_sources

@property
def contains_information_requests(self):
"""Returns true if there are information requests in the dataset"""
return len(self.information_requests.all()) > 0

def get_graphql_contains_information_requests(self):
"""Returns true if there are information requests in the dataset for graphql"""
return self.contains_information_requests

@property
def table_last_updated_at(self):
updates = [
Expand All @@ -814,9 +757,6 @@ def table_last_updated_at(self):
] # fmt: skip
return max(updates) if updates else None

def get_graphql_table_last_updated_at(self):
return self.table_last_updated_at

@property
def raw_data_source_last_updated_at(self):
updates = [
Expand All @@ -825,9 +765,6 @@ def raw_data_source_last_updated_at(self):
] # fmt: skip
return max(updates) if updates else None

def get_graphql_raw_data_source_last_updated_at(self):
return self.raw_data_source_last_updated_at


class Update(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid4)
Expand Down Expand Up @@ -984,9 +921,6 @@ def gbq_slug(self):
table = cloud_table.gcp_table_id
return f"basedosdados.{dataset}.{table}"

def get_graphql_gbq_slug(self):
return self.gbq_slug

@property
def gcs_slug(self):
"""Get the slug used in Google Cloud Storage"""
Expand All @@ -995,19 +929,12 @@ def gcs_slug(self):
table = cloud_table.gcp_table_id
return f"staging/{dataset}/{table}"

def get_graphql_gcs_slug(self):
return self.gcs_slug

@property
def partitions(self):
"""Returns a list of columns used to partition the table"""
partitions_list = [p.name for p in self.columns.all().filter(is_partition=True)]
return ", ".join(partitions_list)

def get_graphql_partitions(self):
"""Returns a list of columns used to partition the table"""
return self.partitions

@property
def contains_closed_data(self):
"""Returns true if there are columns with closed coverages"""
Expand All @@ -1022,10 +949,6 @@ def contains_closed_data(self):

return closed_data

def get_graphql_contains_closed_data(self):
"""Returns true if there are columns with closed coverages to be used in graphql"""
return self.contains_closed_data

@property
def full_coverage(self) -> str:
"""
Expand Down Expand Up @@ -1104,11 +1027,33 @@ def full_coverage(self) -> str:

return json.dumps(full_coverage)

def get_graphql_full_coverage(self):
return self.full_coverage

@property
def neighbors(self):
def neighbors(self) -> list[dict]:
"""Similiar tables and columns
- Tables and columns with similar directories
- Tables and columns with similar coverages or tags
"""
all_neighbors = []
for columns, table, dataset, score in self.get_neighbors():
column_id = []
column_name = []
for column in columns:
column_id.append(str(column.id))
column_name.append(column.name)
all_neighbors.append(
{
"column_id": column_id,
"column_name": column_name,
"table_id": str(table.id),
"table_name": table.name,
"dataset_id": str(dataset.id),
"dataset_name": dataset.name,
"score": score,
}
)
return all_neighbors

def get_neighbors(self):
"""Similiar tables and columns
- Tables and columns with similar directories
- Tables and columns with similar coverages or tags
Expand Down Expand Up @@ -1141,35 +1086,11 @@ def neighbors(self):

return sorted(all_neighbors, key=lambda item: item[-1])[::-1][:20]

def get_graphql_neighbors(self) -> list[dict]:
all_neighbors = []
for columns, table, dataset, score in self.neighbors:
column_id = []
column_name = []
for column in columns:
column_id.append(str(column.id))
column_name.append(column.name)
all_neighbors.append(
{
"column_id": column_id,
"column_name": column_name,
"table_id": str(table.id),
"table_name": table.name,
"dataset_id": str(dataset.id),
"dataset_name": dataset.name,
"score": score,
}
)
return all_neighbors

@property
def last_updated_at(self):
updates = [u.latest for u in self.updates.all() if u.latest]
return max(updates) if updates else None

def get_graphql_last_updated_at(self):
return self.last_updated_at

def similarity_of_area(self, other: "Table"):
count_all = 0
count_yes = 0
Expand Down Expand Up @@ -1369,9 +1290,6 @@ def full_coverage(self) -> str:

return json.dumps(column_full_coverage)

def get_graphql_full_coverage(self):
return self.full_coverage

def clean(self) -> None:
"""Clean method for Column model"""
errors = {}
Expand Down Expand Up @@ -1581,9 +1499,6 @@ def last_updated_at(self):
updates = [u.latest for u in self.updates.all() if u.latest]
return max(updates) if updates else None

def get_graphql_last_updated_at(self):
return self.last_updated_at


class InformationRequest(BaseModel, OrderedModel):
"""Model definition for InformationRequest."""
Expand Down
30 changes: 17 additions & 13 deletions bd_api/custom/graphql_auto.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,31 +377,35 @@ def build_query_objs(application_name: str):
def get_type(model, attr):
"""Get type of an attribute of a class"""
try:
name = getattr(model, attr)
name = get_type_hints(name)
name = name.get("return", "")
func = getattr(model, attr)
func = getattr(func, "fget")
hint = get_type_hints(func)
name = hint.get("return")
return str(name)
except Exception:
return ""

def match_type(model, attr):
"""Match python types to graphene types"""
if "list" in get_type(model, attr):
if "int" in get_type(model, attr):
return partial(List, of_type=Int)
if "str" in get_type(model, attr):
return partial(List, of_type=String)
if "int" in get_type(model, attr):
return partial(List, of_type=Int)
if "str" in get_type(model, attr):
return partial(List, of_type=String)
if "list[int]" in get_type(model, attr):
return partial(List, of_type=Int)
if "list[str]" in get_type(model, attr):
return partial(List, of_type=String)
if "dict" in get_type(model, attr):
return GenericScalar
return String

def build_custom_attrs(model, attrs):
attr_prefix = "get_graphql_"
for attr in dir(model):
if attr.startswith(attr_prefix):
attr_type = match_type(model, attr)
attr_name = attr.split(attr_prefix)[1]
attrs.update({attr_name: attr_type(source=attr)})
attr_func = getattr(model, attr)
if isinstance(attr_func, property):
if attr not in model.graphql_fields_blacklist:
attr_type = match_type(model, attr)
attrs.update({attr: attr_type(source=attr, description=attr_func.__doc__)})
return attrs

queries = {}
Expand Down
1 change: 1 addition & 0 deletions bd_api/custom/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"created_at",
"updated_at",
"deleted_at",
"pk",
"id",
"order",
"_field_status",
Expand Down

0 comments on commit 8b07e26

Please sign in to comment.