Skip to content

Commit

Permalink
update views
Browse files Browse the repository at this point in the history
  • Loading branch information
micpst committed Aug 19, 2024
1 parent d21f4e1 commit e473cc4
Showing 1 changed file with 138 additions and 25 deletions.
163 changes: 138 additions & 25 deletions benchmarks/sql/bench/views/structured/superhero.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from typing import Literal

from sqlalchemy import ColumnElement, Engine, Select, func, select
from sqlalchemy import ColumnElement, Engine, Float, Select, case, cast, func, select
from sqlalchemy.ext.declarative import DeferredReflection
from sqlalchemy.orm import aliased, declarative_base

Expand Down Expand Up @@ -280,17 +280,36 @@ def filter_by_missing_publisher(self) -> ColumnElement:
return Superhero.publisher_id == None


class SuperheroColourFilterMixin:
class SuperheroAggregationMixin:
"""
Mixin for filtering the view by the superhero colour attributes.
Mixin for aggregating the view by the superhero attributes.
"""

def __init__(self, *args, **kwargs) -> None:
self.eye_colour = aliased(Colour)
self.hair_colour = aliased(Colour)
self.skin_colour = aliased(Colour)
@view_aggregation()
def count_superheroes(self) -> Select:
"""
Counts the number of superheros.
super().__init__(*args, **kwargs)
Returns:
The superheros count.
"""
return self.data.with_only_columns(func.count(Superhero.id).label("count_superheroes")).group_by(Superhero.id)

@view_aggregation()
def average_height(self) -> Select:
"""
Averages the height of the superheros.
Returns:
The superheros average height.
"""
return self.data.with_only_columns(func.avg(Superhero.height_cm).label("average_height")).group_by(Superhero.id)


class SuperheroColourFilterMixin:
"""
Mixin for filtering the view by the superhero colour attributes.
"""

@view_filter()
def filter_by_eye_colour(self, eye_colour: str) -> ColumnElement:
Expand Down Expand Up @@ -352,6 +371,31 @@ def filter_by_same_hair_and_skin_colour(self) -> ColumnElement:
return self.hair_colour.colour == self.skin_colour.colour


class SuperheroColourAggregationMixin:
"""
Mixin for aggregating the view by the superhero colour attributes.
"""

@view_aggregation()
def percentage_of_eye_colour(self, eye_colour: str) -> Select:
"""
Calculates the percentage of objects with eye colour.
Args:
eye_colour: The eye colour of the object.
Returns:
The percentage of objects with eye colour.
"""
return self.data.with_only_columns(
(
cast(func.count(case((self.eye_colour.colour == eye_colour, Superhero.id), else_=None)), Float)
* 100
/ func.count(Superhero.id)
).label(f"percentage_of_{eye_colour.lower()}")
)


class PublisherFilterMixin:
"""
Mixin for filtering the view by the publisher attributes.
Expand All @@ -371,6 +415,31 @@ def filter_by_publisher_name(self, publisher_name: str) -> ColumnElement:
return Publisher.publisher_name == publisher_name


class PublisherAggregationMixin:
"""
Mixin for aggregating the view by the publisher attributes.
"""

@view_aggregation()
def percentage_of_publisher(self, publisher_name: str) -> Select:
"""
Calculates the percentage of objects with publisher.
Args:
publisher_name: The name of the publisher.
Returns:
The percentage of objects with publisher.
"""
return self.data.with_only_columns(
(
cast(func.count(case((Publisher.publisher_name == publisher_name, Superhero.id), else_=None)), Float)
* 100
/ func.count(Superhero.id)
).label(f"percentage_of_{publisher_name.lower()}")
)


class AlignmentFilterMixin:
"""
Mixin for filtering the view by the alignment attributes.
Expand All @@ -390,6 +459,31 @@ def filter_by_alignment(self, alignment: Literal["Good", "Bad", "Neutral", "N/A"
return Alignment.alignment == alignment


class AlignmentAggregationMixin:
"""
Mixin for aggregating the view by the alignment.
"""

@view_aggregation()
def percentage_of_alignment(self, alignment: Literal["Good", "Bad", "Neutral", "N/A"]) -> Select:
"""
Calculates the percentage of objects with alignment.
Args:
alignment: The alignment of the object.
Returns:
The percentage of objects with alignment.
"""
return self.data.with_only_columns(
(
cast(func.count(case((Alignment.alignment == alignment, Superhero.id), else_=None)), Float)
* 100
/ func.count(Superhero.id)
).label(f"percentage_of_{alignment.lower()}")
)


class GenderFilterMixin:
"""
Mixin for filtering the view by the gender.
Expand All @@ -409,48 +503,61 @@ def filter_by_gender(self, gender: Literal["Male", "Female", "N/A"]) -> ColumnEl
return Gender.gender == gender


class RaceFilterMixin:
class GenderAggregationMixin:
"""
Mixin for filtering the view by the race.
Mixin for aggregating the view by the gender.
"""

@view_filter()
def filter_by_race(self, race: str) -> ColumnElement:
@view_aggregation()
def percentage_of_gender(self, gender: Literal["Male", "Female", "N/A"]) -> Select:
"""
Filters the view by the object race.
Calculates the percentage of objects with gender.
Args:
race: The race of the object.
gender: The gender of the object.
Returns:
The filter condition.
"""
return Race.race == race
The percentage of objects with gender.
"""
return self.data.with_only_columns(
(
cast(func.count(case((Gender.gender == gender, Superhero.id), else_=None)), Float)
* 100
/ func.count(Superhero.id)
).label(f"percentage_of_{gender.lower()}")
)


class SuperheroAggregationMixin:
class RaceFilterMixin:
"""
Mixin for aggregating the view by the superhero attributes.
Mixin for filtering the view by the race.
"""

@view_aggregation()
def count_superheroes(self) -> Select:
@view_filter()
def filter_by_race(self, race: str) -> ColumnElement:
"""
Counts the number of superheros.
Filters the view by the object race.
Args:
race: The race of the object.
Returns:
The superheros count.
The filter condition.
"""
return self.data.with_only_columns(func.count(Superhero.id).label("count_superheroes")).group_by(Superhero.id)
return Race.race == race


class SuperheroView(
DBInitMixin,
SuperheroFilterMixin,
SuperheroAggregationMixin,
SuperheroFilterMixin,
SuperheroColourAggregationMixin,
SuperheroColourFilterMixin,
AlignmentAggregationMixin,
AlignmentFilterMixin,
GenderAggregationMixin,
GenderFilterMixin,
PublisherAggregationMixin,
PublisherFilterMixin,
RaceFilterMixin,
SqlAlchemyBaseView,
Expand All @@ -460,6 +567,12 @@ class SuperheroView(
publisher name, gender, race, alignment, eye colour, hair colour, skin colour.
"""

def __init__(self, *args, **kwargs) -> None:
self.eye_colour = aliased(Colour)
self.hair_colour = aliased(Colour)
self.skin_colour = aliased(Colour)
super().__init__(*args, **kwargs)

def get_select(self) -> Select:
"""
Initializes the select object for the view.
Expand Down

0 comments on commit e473cc4

Please sign in to comment.