API: only one column to store record values

This commit is contained in:
Sam 2018-05-12 21:31:05 +02:00
parent 5d6a095348
commit 55c2cd54a3
6 changed files with 189 additions and 21 deletions

View File

@ -1,6 +1,7 @@
import datetime import datetime
from mpwo_api import db from mpwo_api import db
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.types import Enum from sqlalchemy.types import Enum
record_types = [ record_types = [
@ -64,8 +65,8 @@ class Activity(db.Model):
max_alt = db.Column(db.Numeric(5, 2), nullable=True) # meters max_alt = db.Column(db.Numeric(5, 2), nullable=True) # meters
descent = db.Column(db.Numeric(5, 2), nullable=True) # meters descent = db.Column(db.Numeric(5, 2), nullable=True) # meters
ascent = db.Column(db.Numeric(5, 2), nullable=True) # meters ascent = db.Column(db.Numeric(5, 2), nullable=True) # meters
max_speed = db.Column(db.Numeric(5, 3), nullable=True) # km/h max_speed = db.Column(db.Numeric(5, 2), nullable=True) # km/h
ave_speed = db.Column(db.Numeric(5, 3), nullable=True) # km/h ave_speed = db.Column(db.Numeric(5, 2), nullable=True) # km/h
records = db.relationship('Record', records = db.relationship('Record',
lazy=True, lazy=True,
backref=db.backref('activities', lazy='joined')) backref=db.backref('activities', lazy='joined'))
@ -125,8 +126,7 @@ class Record(db.Model):
nullable=False) nullable=False)
record_type = db.Column(Enum(*record_types, name="record_types")) record_type = db.Column(Enum(*record_types, name="record_types"))
activity_date = db.Column(db.DateTime, nullable=False) activity_date = db.Column(db.DateTime, nullable=False)
value_interval = db.Column(db.Interval, nullable=True) _value = db.Column("value", db.Integer, nullable=True)
value_float = db.Column(db.Numeric(5, 3), nullable=True)
def __str__(self): def __str__(self):
return str(self.sports.label) + \ return str(self.sports.label) + \
@ -140,7 +140,36 @@ class Record(db.Model):
self.record_type = record_type self.record_type = record_type
self.activity_date = activity.activity_date self.activity_date = activity.activity_date
@hybrid_property
def value(self):
if self._value is None:
return None
if self.record_type == 'LD':
return datetime.timedelta(seconds=self._value)
elif self.record_type in ['AS', 'MS']:
return float(self._value / 100)
else: # 'FD'
return float(self._value / 1000)
@value.setter
def value(self, val):
if self.record_type == 'LD':
hours, minutes, seconds = str(val).split(':')
self._value = int(hours) * 3600 + int(minutes) * 60 + int(seconds)
elif self.record_type in ['AS', 'MS']:
self._value = int(val * 100)
else: # 'FD'
self._value = int(val * 1000)
def serialize(self): def serialize(self):
if self.value is None:
value = None
elif self.record_type in ['AS', 'FD', 'MS']:
value = float(self.value)
else: # 'LD'
value = str(self.value)
return { return {
"id": self.id, "id": self.id,
"user_id": self.user_id, "user_id": self.user_id,
@ -148,8 +177,5 @@ class Record(db.Model):
"activity_id": self.activity_id, "activity_id": self.activity_id,
"record_type": self.record_type, "record_type": self.record_type,
"activity_date": self.activity_date, "activity_date": self.activity_date,
"value_interval": str( "value": value,
self.value_interval) if self.value_interval else None,
"value_float": str(
self.value_float) if self.value_float else None,
} }

View File

@ -42,11 +42,11 @@ def test_add_an_activity_gpx(app):
assert 1 == data['data']['activities'][0]['sport_id'] assert 1 == data['data']['activities'][0]['sport_id']
assert '0:04:10' == data['data']['activities'][0]['duration'] assert '0:04:10' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['ascent'] == 0.4 assert data['data']['activities'][0]['ascent'] == 0.4
assert data['data']['activities'][0]['ave_speed'] == 4.602 assert data['data']['activities'][0]['ave_speed'] == 4.6
assert data['data']['activities'][0]['descent'] == 23.4 assert data['data']['activities'][0]['descent'] == 23.4
assert data['data']['activities'][0]['distance'] == 0.32 assert data['data']['activities'][0]['distance'] == 0.32
assert data['data']['activities'][0]['max_alt'] == 998.0 assert data['data']['activities'][0]['max_alt'] == 998.0
assert data['data']['activities'][0]['max_speed'] == 5.086 assert data['data']['activities'][0]['max_speed'] == 5.09
assert data['data']['activities'][0]['min_alt'] == 975.0 assert data['data']['activities'][0]['min_alt'] == 975.0
assert data['data']['activities'][0]['moving'] == '0:04:10' assert data['data']['activities'][0]['moving'] == '0:04:10'
assert data['data']['activities'][0]['pauses'] is None assert data['data']['activities'][0]['pauses'] is None
@ -99,11 +99,11 @@ def test_get_an_activity_with_gpx(app):
assert 1 == data['data']['activities'][0]['sport_id'] assert 1 == data['data']['activities'][0]['sport_id']
assert '0:04:10' == data['data']['activities'][0]['duration'] assert '0:04:10' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['ascent'] == 0.4 assert data['data']['activities'][0]['ascent'] == 0.4
assert data['data']['activities'][0]['ave_speed'] == 4.602 assert data['data']['activities'][0]['ave_speed'] == 4.6
assert data['data']['activities'][0]['descent'] == 23.4 assert data['data']['activities'][0]['descent'] == 23.4
assert data['data']['activities'][0]['distance'] == 0.32 assert data['data']['activities'][0]['distance'] == 0.32
assert data['data']['activities'][0]['max_alt'] == 998.0 assert data['data']['activities'][0]['max_alt'] == 998.0
assert data['data']['activities'][0]['max_speed'] == 5.086 assert data['data']['activities'][0]['max_speed'] == 5.09
assert data['data']['activities'][0]['min_alt'] == 975.0 assert data['data']['activities'][0]['min_alt'] == 975.0
assert data['data']['activities'][0]['moving'] == '0:04:10' assert data['data']['activities'][0]['moving'] == '0:04:10'
assert data['data']['activities'][0]['pauses'] is None assert data['data']['activities'][0]['pauses'] is None

View File

@ -58,11 +58,11 @@ def test_edit_an_activity_with_gpx(app):
assert 2 == data['data']['activities'][0]['sport_id'] assert 2 == data['data']['activities'][0]['sport_id']
assert '0:04:10' == data['data']['activities'][0]['duration'] assert '0:04:10' == data['data']['activities'][0]['duration']
assert data['data']['activities'][0]['ascent'] == 0.4 assert data['data']['activities'][0]['ascent'] == 0.4
assert data['data']['activities'][0]['ave_speed'] == 4.602 assert data['data']['activities'][0]['ave_speed'] == 4.6
assert data['data']['activities'][0]['descent'] == 23.4 assert data['data']['activities'][0]['descent'] == 23.4
assert data['data']['activities'][0]['distance'] == 0.32 assert data['data']['activities'][0]['distance'] == 0.32
assert data['data']['activities'][0]['max_alt'] == 998.0 assert data['data']['activities'][0]['max_alt'] == 998.0
assert data['data']['activities'][0]['max_speed'] == 5.086 assert data['data']['activities'][0]['max_speed'] == 5.09
assert data['data']['activities'][0]['min_alt'] == 975.0 assert data['data']['activities'][0]['min_alt'] == 975.0
assert data['data']['activities'][0]['moving'] == '0:04:10' assert data['data']['activities'][0]['moving'] == '0:04:10'
assert data['data']['activities'][0]['pauses'] is None assert data['data']['activities'][0]['pauses'] is None
@ -263,11 +263,11 @@ def test_edit_an_activity_wo_gpx_partial(app):
assert data['data']['activities'][0]['sport_id'] == 1 assert data['data']['activities'][0]['sport_id'] == 1
assert data['data']['activities'][0]['duration'] == '0:17:04' assert data['data']['activities'][0]['duration'] == '0:17:04'
assert data['data']['activities'][0]['ascent'] is None assert data['data']['activities'][0]['ascent'] is None
assert data['data']['activities'][0]['ave_speed'] == 35.156 assert data['data']['activities'][0]['ave_speed'] == 35.16
assert data['data']['activities'][0]['descent'] is None assert data['data']['activities'][0]['descent'] is None
assert data['data']['activities'][0]['distance'] == 10.0 assert data['data']['activities'][0]['distance'] == 10.0
assert data['data']['activities'][0]['max_alt'] is None assert data['data']['activities'][0]['max_alt'] is None
assert data['data']['activities'][0]['max_speed'] == 35.156 assert data['data']['activities'][0]['max_speed'] == 35.16
assert data['data']['activities'][0]['min_alt'] is None assert data['data']['activities'][0]['min_alt'] is None
assert data['data']['activities'][0]['moving'] is None # no calculated assert data['data']['activities'][0]['moving'] is None # no calculated
assert data['data']['activities'][0]['pauses'] is None assert data['data']['activities'][0]['pauses'] is None

View File

@ -65,13 +65,11 @@ def test_get_all_activities_for_authenticated_user(app):
assert 1 == data['data']['records'][0]['sport_id'] assert 1 == data['data']['records'][0]['sport_id']
assert 3 == data['data']['records'][0]['activity_id'] assert 3 == data['data']['records'][0]['activity_id']
assert 'FD' == data['data']['records'][0]['record_type'] assert 'FD' == data['data']['records'][0]['record_type']
assert 'value_interval' in data['data']['records'][0] assert 'value' in data['data']['records'][0]
assert 'value_float' in data['data']['records'][0]
assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['records'][1]['activity_date'] # noqa assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['records'][1]['activity_date'] # noqa
assert 1 == data['data']['records'][1]['user_id'] assert 1 == data['data']['records'][1]['user_id']
assert 2 == data['data']['records'][1]['sport_id'] assert 2 == data['data']['records'][1]['sport_id']
assert 1 == data['data']['records'][1]['activity_id'] assert 1 == data['data']['records'][1]['activity_id']
assert 'LD' == data['data']['records'][1]['record_type'] assert 'LD' == data['data']['records'][1]['record_type']
assert 'value_interval' in data['data']['records'][1] assert 'value' in data['data']['records'][1]
assert 'value_float' in data['data']['records'][1]

View File

@ -23,3 +23,148 @@ def test_add_record(app):
assert 'LD' == record.record_type assert 'LD' == record.record_type
assert '2018-01-01 13:36:00' == str(record.activity_date) assert '2018-01-01 13:36:00' == str(record.activity_date)
assert 'cycling - LD - 2018-01-01' == str(record) assert 'cycling - LD - 2018-01-01' == str(record)
record_serialize = record.serialize()
assert 'id' in record_serialize
assert 'user_id' in record_serialize
assert 'sport_id' in record_serialize
assert 'activity_id' in record_serialize
assert 'record_type' in record_serialize
assert 'activity_date' in record_serialize
assert 'value' in record_serialize
def test_add_records_no_value(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
activity = add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018 13:36', '%d/%m/%Y %H:%M'), # noqa
distance=10,
duration=datetime.timedelta(seconds=1024)
)
record = add_record(1, 1, activity, 'AS')
assert record.value is None
assert record._value is None
record_serialize = record.serialize()
assert record_serialize.get('value') is None
def test_add_as_records(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
activity = add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018 13:36', '%d/%m/%Y %H:%M'), # noqa
distance=10,
duration=datetime.timedelta(seconds=1024)
)
record = add_record(1, 1, activity, 'AS')
# record.value = 4.6
record.value = 4.61
assert isinstance(record.value, float)
assert record.value == 4.61
assert record._value == 461
record_serialize = record.serialize()
assert record_serialize.get('value') == 4.61
assert isinstance(record_serialize.get('value'), float)
def test_add_fd_records(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
activity = add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018 13:36', '%d/%m/%Y %H:%M'), # noqa
distance=10,
duration=datetime.timedelta(seconds=1024)
)
record = add_record(1, 1, activity, 'FD')
record.value = 0.322
assert isinstance(record.value, float)
assert record.value == 0.322
assert record._value == 322
record_serialize = record.serialize()
assert record_serialize.get('value') == 0.322
assert isinstance(record_serialize.get('value'), float)
def test_add_ld_records(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
activity = add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018 13:36', '%d/%m/%Y %H:%M'), # noqa
distance=10,
duration=datetime.timedelta(seconds=1024)
)
record = add_record(1, 1, activity, 'LD')
record.value = activity.duration
assert isinstance(record.value, datetime.timedelta)
assert str(record.value) == '0:17:04'
assert record._value == 1024
record_serialize = record.serialize()
assert record_serialize.get('value') == '0:17:04'
assert isinstance(record_serialize.get('value'), str)
def test_add_ld_records_zero(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
activity = add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018 13:36', '%d/%m/%Y %H:%M'), # noqa
distance=10,
duration=datetime.timedelta(seconds=0)
)
record = add_record(1, 1, activity, 'LD')
record.value = activity.duration
assert isinstance(record.value, datetime.timedelta)
assert str(record.value) == '0:00:00'
assert record._value == 0
record_serialize = record.serialize()
assert record_serialize.get('value') == '0:00:00'
assert isinstance(record_serialize.get('value'), str)
def test_add_ms_records_no_value(app):
add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
activity = add_activity(
user_id=1,
sport_id=1,
activity_date=datetime.datetime.strptime('01/01/2018 13:36', '%d/%m/%Y %H:%M'), # noqa
distance=10,
duration=datetime.timedelta(seconds=1024)
)
record = add_record(1, 1, activity, 'MS')
record.value = 23.5
assert isinstance(record.value, float)
assert record.value == 23.5
assert record._value == 2350
record_serialize = record.serialize()
assert record_serialize.get('value') == 23.5
assert isinstance(record_serialize.get('value'), float)

View File

@ -4,4 +4,3 @@ from mpwo_api.tests.utils import add_user
def test_add_user(app): def test_add_user(app):
user = add_user('test', 'test@test.com', '12345678') user = add_user('test', 'test@test.com', '12345678')
assert '<User \'test\'>' == str(user) assert '<User \'test\'>' == str(user)