Creating access layer for the device and skill settings

- Replaced the function getcwd() for path.dirname(__file__) as a safer solution to get the current folder
 - Created functions to fetch devices using either id or account id
 - Created function get_setting_by_device_id_and_setting_version_hash to fetch a skill setting using the setting version hash and the device id

 The last function hits multiple tables and to avoid trigger a lot of queries we:
 - use a single query to fetch all sections for a given skill and device;
 - use a single query to fetch all settings passing the list of section ids from the previous step;
 - use a single query to fetch all skill settings for a given device and skill
pull/30/head
Matheus Lima 2018-12-26 18:15:52 -03:00
parent f24946ab30
commit acb77b1566
13 changed files with 204 additions and 9 deletions

View File

@ -1 +1 @@
from .account import get_account_by_id
from .account import get_account_by_id

View File

@ -1,10 +1,9 @@
from dataclasses import dataclass
from decimal import Decimal
from os import getcwd, path
from os import path
from selene_util.db import DatabaseQuery, fetch
SQL_DIR = path.join(getcwd(), 'sql')
SQL_DIR = path.join(path.dirname(__file__), 'sql')
@dataclass
@ -12,16 +11,15 @@ class Account(object):
"""Representation of a Mycroft user account."""
id: str
email_address: str
first_name: str
last_name: str
password: str
latitude: Decimal
longitude: Decimal
date_format: str
time_format: str
measurement_system: str
wake_word: str
text_to_speech_id: str
first_name: str = None
last_name: str = None
password: str = None
picture: str = None
def get_account_by_id(db, account_id: str) -> Account:

View File

@ -0,0 +1,2 @@
from .device import get_device_by_id
from .device import get_devices_by_account_id

View File

@ -0,0 +1,54 @@
from datetime import datetime
from dataclasses import dataclass
from os import path
from selene_util.db import DatabaseQuery, fetch
SQL_DIR = path.join(path.dirname(__file__), 'sql')
@dataclass
class Device(object):
"""Representation of a Device"""
id: str
account_id: str
name: str
platform: str = None
enclosure_version: str = None
core_version: str = None
category_id: str = None
location_id: str = None
placement: str = None
last_contact_ts: datetime = None
def get_device_by_id(db, device_id: str) -> Device:
"""Fetch a device using a given device id
:param db: psycopg2 connection to mycroft database
:param device_id: uuid
:return:
"""
query = DatabaseQuery(
file_path=path.join(SQL_DIR, 'get_device_by_id.sql'),
args=dict(device_id=device_id),
singleton=True
)
sql_result = fetch(db, query)
return Device(**sql_result)
def get_devices_by_account_id(db, account_id: str) -> list[Device]:
"""Fetch all devices associated to a user from a given account id
:param db: psycopg2 connection to mycroft database
:param account_id: uuid
:return:
"""
query = DatabaseQuery(
file_path=path.join(SQL_DIR, 'get_devices_by_account_id.sql'),
args=dict(account_id=account_id),
singleton=False
)
sql_results = fetch(db, query)
return list(map(lambda result: Device(**result), sql_results))

View File

@ -0,0 +1 @@
SELECT * FROM device.device WHERE id = %(device_id)s

View File

@ -0,0 +1 @@
SELECT * FROM device.device WHERE account_id = %(account_id)s

View File

@ -0,0 +1 @@
from .db import get_view_connection

View File

@ -9,12 +9,15 @@ Example Usage:
from dataclasses import dataclass
from logging import getLogger
from os import path
from os import environ
from psycopg2 import connect
from psycopg2.extras import RealDictCursor
_log = getLogger(__package__)
DB_HOST = environ['DB_HOST']
def get_sql_from_file(file_path: str) -> str:
"""
@ -39,6 +42,7 @@ def _connect_to_mycroft_db(db_user):
:return: database connection
"""
db = connect(
host=DB_HOST,
dbname='mycroft',
user=db_user,
cursor_factory=RealDictCursor

View File

@ -0,0 +1,3 @@
from .skill import get_setting_sections_by_device_id_and_setting_version
from .skill import get_setting_by_section_id
from .skill import get_setting_by_device_id_and_setting_version_hash

View File

@ -0,0 +1,118 @@
from dataclasses import dataclass
from os import path
from selene_util.db import DatabaseQuery, fetch
SQL_DIR = path.join(path.dirname(__file__), 'sql')
@dataclass
class Setting(object):
"""Representation of a Skill setting"""
id: str
setting_section_id: str
setting: str
setting_type: str
hidden: bool
display_order: int
hint: str = None
label: str = None
placeholder: str = None
options: str = None
default_value: str = None
value: str = None
@dataclass
class SettingSection(object):
"""Representation of a section from a Skill Setting"""
id: str
skill_version_id: str
section: str
display_order: int
description: str = None
settings: list = None
@dataclass
class SkillSetting(object):
"""Representation of the link between a device and a skill setting """
id: str
device_skill_id: str
setting_id: str
value: str = None
def get_setting_sections_by_device_id_and_setting_version(db, device_id, setting_version_hash):
""" Fetch all sections of a skill for a given device and setting version
:param db: psycopg2 connection to the mycroft database
:param device_id: uuid
:param setting_version_hash: version_hash for a given skill setting
:return:
"""
query = DatabaseQuery(
file_path=path.join(SQL_DIR, 'get_setting_sections_by_device_id_and_setting_version.sql'),
args=dict(device_id=device_id, setting_version_hash=setting_version_hash),
singleton=False
)
sql_results = fetch(db, query)
return list(map(lambda result: SettingSection(**result), sql_results))
def get_setting_by_section_id(db, setting_section_ids):
""" Fetch all settings for a given list of section ids
:param db: psycopg2 connection to the mycroft database
:param setting_section_ids: list of section ids
:return:
"""
query = DatabaseQuery(
file_path=path.join(SQL_DIR, 'get_setting_by_section_ids.sql'),
args=dict(setting_section_ids=setting_section_ids),
singleton=False
)
sql_results = fetch(db, query)
return list(map(lambda result: Setting(**result), sql_results))
def get_skill_settings_by_device_id_and_version_hash(db, device_id, setting_version_hash):
"""Fetch the skill settings for a given device and setting version hash
:param db: psycopg2 connection to the mycroft database
:param device_id: uuid
:param setting_version_hash:
:return:
"""
query = DatabaseQuery(
file_path=path.join(SQL_DIR, 'get_skill_setting_by_device_id_and_version_hash.sql'),
args=dict(device_id=device_id, setting_version_hash=setting_version_hash),
singleton=False
)
sql_results = fetch(db, query)
return list(map(lambda result: SkillSetting(**result), sql_results))
def get_setting_by_device_id_and_setting_version_hash(db, device_id, setting_version_hash):
"""Fetch the skill settings filling the setting using the value from the table skill setting
:param db: psycopg2 connection to the mycroft database
:param device_id: uuid
:param setting_version_hash:
:return:
"""
sections = get_setting_sections_by_device_id_and_setting_version(db, device_id, setting_version_hash)
setting_sections_ids = tuple(map(lambda s: s.id, sections))
settings = get_setting_by_section_id(db, setting_sections_ids)
skill_settings = get_skill_settings_by_device_id_and_version_hash(db, device_id, setting_version_hash)
# Fills each setting with the correspondent value from the skill setting
for skill_setting in skill_settings:
s = next(filter(lambda setting: setting.id == skill_setting.setting_id, settings), None)
if s:
s.value = skill_setting.value
# Fills each setting with its list of settings
for section in sections:
section.settings = list(filter(lambda setting: setting.setting_section_id == section.id, settings))
return sections

View File

@ -0,0 +1 @@
SELECT * FROM skill.setting WHERE setting_section_id IN %(setting_section_ids)s

View File

@ -0,0 +1,6 @@
SELECT set_section.* FROM device.device dev
INNER JOIN device.device_skill dev_skill ON dev.id = dev_skill.device_id
INNER JOIN skill.skill skill ON dev_skill.skill_id = skill.id
INNER JOIN skill.setting_version set_version ON skill.id = set_version.skill_id
INNER JOIN skill.setting_section set_section ON set_version.id = set_section.skill_version_id
WHERE dev.id = %(device_id)s AND set_version.version_hash = %(setting_version_hash)s

View File

@ -0,0 +1,6 @@
SELECT skill_set.* FROM device.device dev
JOIN device.device_skill dev_skill ON dev.id = dev_skill.device_id
JOIN device.skill_setting skill_set ON dev_skill.id = skill_set.device_skill_id
JOIN skill.skill skill ON dev_skill.skill_id = skill.id
JOIN skill.setting_version ver ON skill.id = ver.skill_id
WHERE ver.version_hash = %(setting_version_hash)s AND dev.id = %(device_id)s