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 skillpull/30/head
parent
f24946ab30
commit
acb77b1566
|
@ -1 +1 @@
|
|||
from .account import get_account_by_id
|
||||
from .account import get_account_by_id
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
from .device import get_device_by_id
|
||||
from .device import get_devices_by_account_id
|
|
@ -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))
|
|
@ -0,0 +1 @@
|
|||
SELECT * FROM device.device WHERE id = %(device_id)s
|
|
@ -0,0 +1 @@
|
|||
SELECT * FROM device.device WHERE account_id = %(account_id)s
|
|
@ -0,0 +1 @@
|
|||
from .db import get_view_connection
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
SELECT * FROM skill.setting WHERE setting_section_id IN %(setting_section_ids)s
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue