Add Lot.parents

This commit is contained in:
Xavier Bustamante Talavera 2018-09-12 14:53:14 +02:00
parent aa52367f03
commit f7112d7fe1
5 changed files with 38 additions and 19 deletions

View File

@ -2,9 +2,9 @@ import uuid
from datetime import datetime
from flask import g
from sqlalchemy import TEXT
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import aliased
from sqlalchemy.sql import expression
from sqlalchemy.sql import expression as exp
from sqlalchemy_utils import LtreeType
from sqlalchemy_utils.types.ltree import LQUERY
from teal.db import UUIDLtree
@ -53,22 +53,32 @@ class Lot(Thing):
Path.add(self.id, child)
db.session.refresh(self) # todo is this useful?
def remove_child(self, child: 'Lot'):
def remove_child(self, child):
if isinstance(child, Lot):
Path.delete(self.id, child.id)
else:
assert isinstance(child, uuid.UUID)
Path.delete(self.id, child)
@property
def children(self):
"""The children lots."""
# From https://stackoverflow.com/a/41158890
# todo test
cls = self.__class__
exp = '*.{}.*{{1}}'.format(UUIDLtree.convert(self.id))
child_lots = aliased(Lot)
id = UUIDLtree.convert(self.id)
return self.query \
.join(cls.paths) \
.filter(Path.path.lquery(expression.cast(exp, LQUERY))) \
.join(child_lots, Path.lot)
.join(self.__class__.paths) \
.filter(Path.path.lquery(exp.cast('*.{}.*{{1}}'.format(id), LQUERY)))
@property
def parents(self):
"""The parent lots."""
id = UUIDLtree.convert(self.id)
i = db.func.index(Path.path, id)
parent_id = db.func.replace(exp.cast(db.func.subpath(Path.path, i - 1, i), TEXT), '_', '-')
join_clause = parent_id == exp.cast(Lot.id, TEXT)
return self.query.join(Path, join_clause).filter(
Path.path.lquery(exp.cast('*{{1}}.{}.*'.format(id), LQUERY))
)
def __contains__(self, child: 'Lot'):
return Path.has_lot(self.id, child.id)

View File

@ -31,7 +31,7 @@ class Lot(Thing):
def add_child(self, child: Union[Lot, uuid.UUID]):
pass
def remove_child(self, child: Lot):
def remove_child(self, child: Union[Lot, uuid.UUID]):
pass
@classmethod
@ -42,6 +42,10 @@ class Lot(Thing):
def children(self) -> LotQuery:
pass
@property
def parents(self) -> LotQuery:
pass
class Path:
id = ... # type: Column

View File

@ -12,6 +12,5 @@ class Lot(Thing):
name = f.String(validate=f.validate.Length(max=STR_SIZE), required=True)
closed = f.Boolean(missing=False, description=m.Lot.closed.comment)
devices = NestedOn(Device, many=True, dump_only=True)
children = NestedOn('Lot',
many=True,
dump_only=True)
children = NestedOn('Lot', many=True, dump_only=True)
parents = NestedOn('Lot', many=True, dump_only=True)

View File

@ -49,6 +49,7 @@ class LotBaseChildrenView(View):
lot = self.get_lot(id)
self._post(lot, self.get_ids())
db.session.commit()
ret = self.schema.jsonify(lot)
ret.status_code = 201
return ret

View File

@ -210,10 +210,15 @@ def test_post_get_lot(user: UserClient):
def test_post_add_children_view(user: UserClient):
"""Tests adding children lots to a lot through the view."""
l, _ = user.post(({'name': 'Parent'}), res=Lot)
parent, _ = user.post(({'name': 'Parent'}), res=Lot)
child, _ = user.post(({'name': 'Child'}), res=Lot)
l, _ = user.post({}, res=Lot, item='{}/children'.format(l['id']), query=[('id', child['id'])])
assert l['children'][0]['id'] == child['id']
parent, _ = user.post({},
res=Lot,
item='{}/children'.format(parent['id']),
query=[('id', child['id'])])
assert parent['children'][0]['id'] == child['id']
child, _ = user.get(res=Lot, item=child['id'])
assert child['parents'][0]['id'] == parent['id']
@pytest.mark.xfail(reason='Just develop the test')