diff --git a/platypush/plugins/db/__init__.py b/platypush/plugins/db/__init__.py new file mode 100644 index 00000000..f392d8c2 --- /dev/null +++ b/platypush/plugins/db/__init__.py @@ -0,0 +1,79 @@ +import logging + +from sqlalchemy import create_engine + +from platypush.message.response import Response + +from .. import Plugin + +class DbPlugin(Plugin): + """ Database plugin. It allows you to programmatically select, insert, + update and delete records on a database backend through requests, + procedures and event hooks """ + + engine = None + + def __init__(self, engine=None, *args, **kwargs): + """ + Params: + engine -- Default SQLAlchemy connection engine string + (e.g. sqlite:///:memory: or mysql://user:pass@localhost/test) + that will be used. You can override this value in your statement actions + + args, kwargs -- Extra arguments for sqlalchemy.create_engine + """ + + self.engine = self._get_engine(engine, *args, **kwargs) + + + def _get_engine(self, engine=None, *args, **kwargs): + if engine: + return create_engine(engine, *args, **kwargs) + else: + return self.engine + + def execute(self, statement, engine=None, *args, **kwargs): + """ Executes a generic SQL statement """ + + engine = self._get_engine(engine, *args, **kwargs) + + with engine.connect() as connection: + result = connection.execute(statement) + + return Response() + + + def select(self, query, engine=None, *args, **kwargs): + """ Returns rows (as a list of dicts) given a query """ + + engine = self._get_engine(engine, *args, **kwargs) + + with engine.connect() as connection: + result = connection.execute(query) + columns = result.keys() + rows = [ + { columns[i]: row[i] for i in range(0, len(columns)) } + for row in result.fetchall() + ] + + return Response(output=rows) + + + def insert(self, table, records, engine=None, *args, **kwargs): + """ Inserts records (as a list of dicts) into a table """ + + engine = self._get_engine(engine, *args, **kwargs) + + for record in records: + statement = 'INSERT INTO {}({}) VALUES({})'.format \ + (table, ','.join(record.keys()), + ','.join([ ':' + key for key in record.keys() ])) + + with engine.connect() as connection: + connection.execute(statement, **record) + + return Response() + + +# vim:sw=4:ts=4:et: + diff --git a/requirements.txt b/requirements.txt index c65c0d08..62753dd5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,6 +11,9 @@ websocket-client # HTTP backend support flask +# Database plugin support +sqlalchemy + # Philips Hue plugin support phue diff --git a/setup.py b/setup.py index d5dfe516..ea0b62ef 100755 --- a/setup.py +++ b/setup.py @@ -64,6 +64,7 @@ setup( 'Support for Apache Kafka backend': ['kafka-python'], 'Support for Pushbullet backend': ['requests', 'websocket-client'], 'Support for HTTP backend': ['flask'], + 'Support for database plugin': ['sqlalchemy'], 'Support for Philips Hue plugin': ['phue'], 'Support for MPD/Mopidy music server plugin': ['python-mpd2'], 'Support for Belkin WeMo Switch plugin': ['ouimeaux'], @@ -71,7 +72,7 @@ setup( 'Support for OMXPlayer plugin': ['omxplayer'], 'Support for YouTube in the OMXPlayer plugin': ['youtube-dl'], 'Support for Google Assistant': ['google-assistant-sdk[samples]'], - # 'Support for Flic buttons': ['-e git+https://github.com/50ButtonsEach/fliclib-linux-hci'] + 'Support for Flic buttons': ['git+ssh://git@github.com/50ButtonsEach/fliclib-linux-hci'] }, )