Make Grid.gridify() use only pickup addresses
- ensure a `Restaurant` only has one unique `Order.pickup_address` - rework `Grid.gridify()` so that only pickup addresses are assigned into `Pixel`s - include database migrations to ensure the data adhere to these tighter constraints
This commit is contained in:
parent
0c1ff5338d
commit
1bfc7db916
11 changed files with 519 additions and 61 deletions
|
|
@ -8,7 +8,7 @@ from urban_meal_delivery.console import decorators
|
|||
|
||||
|
||||
@click.command()
|
||||
@decorators.db_revision('888e352d7526')
|
||||
@decorators.db_revision('e86290e7305e')
|
||||
def gridify() -> None: # pragma: no cover note:b1f68d24
|
||||
"""Create grids for all cities.
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class Address(meta.Base):
|
|||
|
||||
# Relationships
|
||||
city = orm.relationship('City', back_populates='addresses')
|
||||
restaurant = orm.relationship('Restaurant', back_populates='address', uselist=False)
|
||||
restaurants = orm.relationship('Restaurant', back_populates='address')
|
||||
orders_picked_up = orm.relationship(
|
||||
'Order',
|
||||
back_populates='pickup_address',
|
||||
|
|
|
|||
|
|
@ -54,11 +54,12 @@ class Grid(meta.Base):
|
|||
return round((self.side_length ** 2) / 1_000_000, 1)
|
||||
|
||||
@classmethod
|
||||
def gridify(cls, city: db.City, side_length: int) -> db.Grid:
|
||||
def gridify(cls, city: db.City, side_length: int) -> db.Grid: # noqa:WPS210
|
||||
"""Create a fully populated `Grid` for a `city`.
|
||||
|
||||
The `Grid` contains only `Pixel`s that have at least one `Address`.
|
||||
`Address` objects outside the `city`'s viewport are discarded.
|
||||
The `Grid` contains only `Pixel`s that have at least one
|
||||
`Order.pickup_address`. `Address` objects outside the `.city`'s
|
||||
viewport are discarded.
|
||||
|
||||
Args:
|
||||
city: city for which the grid is created
|
||||
|
|
@ -72,7 +73,14 @@ class Grid(meta.Base):
|
|||
# `Pixel`s grouped by `.n_x`-`.n_y` coordinates.
|
||||
pixels = {}
|
||||
|
||||
for address in city.addresses:
|
||||
pickup_addresses = ( # noqa:ECE:001
|
||||
db.session.query(db.Address)
|
||||
.join(db.Order, db.Address.id == db.Order.pickup_address_id)
|
||||
.filter(db.Address.city == city)
|
||||
.all()
|
||||
)
|
||||
|
||||
for address in pickup_addresses:
|
||||
# Check if an `address` is not within the `city`'s viewport, ...
|
||||
not_within_city_viewport = (
|
||||
address.x < 0
|
||||
|
|
|
|||
|
|
@ -79,12 +79,6 @@ class Order(meta.Base): # noqa:WPS214
|
|||
sa.ForeignKeyConstraint(
|
||||
['customer_id'], ['customers.id'], onupdate='RESTRICT', ondelete='RESTRICT',
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['restaurant_id'],
|
||||
['restaurants.id'],
|
||||
onupdate='RESTRICT',
|
||||
ondelete='RESTRICT',
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['courier_id'], ['couriers.id'], onupdate='RESTRICT', ondelete='RESTRICT',
|
||||
),
|
||||
|
|
@ -94,6 +88,14 @@ class Order(meta.Base): # noqa:WPS214
|
|||
onupdate='RESTRICT',
|
||||
ondelete='RESTRICT',
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
# This foreign key ensures that there is only
|
||||
# one `.pickup_address` per `.restaurant`
|
||||
['restaurant_id', 'pickup_address_id'],
|
||||
['restaurants.id', 'restaurants.address_id'],
|
||||
onupdate='RESTRICT',
|
||||
ondelete='RESTRICT',
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
['delivery_address_id'],
|
||||
['addresses.id'],
|
||||
|
|
@ -302,7 +304,11 @@ class Order(meta.Base): # noqa:WPS214
|
|||
|
||||
# Relationships
|
||||
customer = orm.relationship('Customer', back_populates='orders')
|
||||
restaurant = orm.relationship('Restaurant', back_populates='orders')
|
||||
restaurant = orm.relationship(
|
||||
'Restaurant',
|
||||
back_populates='orders',
|
||||
primaryjoin='Restaurant.id == Order.restaurant_id',
|
||||
)
|
||||
courier = orm.relationship('Courier', back_populates='orders')
|
||||
pickup_address = orm.relationship(
|
||||
'Address',
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class Pixel(meta.Base):
|
|||
Square pixels aggregate `Address` objects within a `City`.
|
||||
Every `Address` belongs to exactly one `Pixel` in a `Grid`.
|
||||
|
||||
Every `Pixel` has a unique "coordinate" within the `Grid`.
|
||||
Every `Pixel` has a unique `n_x`-`n_y` coordinate within the `Grid`.
|
||||
"""
|
||||
|
||||
__tablename__ = 'pixels'
|
||||
|
|
|
|||
|
|
@ -34,10 +34,12 @@ class Restaurant(meta.Base):
|
|||
'0 <= estimated_prep_duration AND estimated_prep_duration <= 2400',
|
||||
name='realistic_estimated_prep_duration',
|
||||
),
|
||||
# Needed by a `ForeignKeyConstraint` in `Order`.
|
||||
sa.UniqueConstraint('id', 'address_id'),
|
||||
)
|
||||
|
||||
# Relationships
|
||||
address = orm.relationship('Address', back_populates='restaurant')
|
||||
address = orm.relationship('Address', back_populates='restaurants')
|
||||
orders = orm.relationship('Order', back_populates='restaurant')
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue