@@ -0,0 +1,2664 @@
+import json%0Afrom typing import Any, Dict, Optional, Union%0A%0Aimport sqlalchemy%0Afrom sqlalchemy.ext.automap import automap_base%0Afrom sqlalchemy.sql import text%0A%0Afrom ..interfaces.context import Context%0Afrom ..interfaces.inputter import Inputter%0Afrom ..interfaces.outputter import Outputter%0A%0ARow = Optional%5BDict%5D%0A%0A%0Aclass SQLInputter(Inputter%5BRow%5D):%0A    def __init__(%0A        self, url: str, *, table: Optional%5Bstr%5D = None, query: Optional%5Bstr%5D = None%0A    ) -%3E None:%0A        if query is None and table is None:%0A            raise NotImplementedError%0A        if query is not None and table is not None:%0A            raise NotImplementedError%0A        self.engine = sqlalchemy.create_engine(url)%0A        if table is not None:%0A            metadata = sqlalchemy.MetaData()%0A            metadata.reflect(self.engine, only=%5Btable%5D)%0A            Base = automap_base(metadata=metadata)%0A            Base.prepare()%0A            select_query = metadata.tables%5Btable%5D.select()%0A        else:%0A            select_query = None%0A%0A        if select_query is not None:%0A            self.result = self.engine.execute(select_query)%0A        else:%0A            self.result = self.engine.execute(query)%0A        self.keys = list(self.result.keys())%0A%0A    def read(self) -%3E Context%5BRow%5D:%0A        r = self.result.fetchone()%0A        if r is None:%0A            return Context(None)%0A        p = dict(zip(self.keys, list(r)))%0A        return Context(p)%0A%0A%0Aclass SQLOutputter(Outputter%5BAny%5D):%0A    def __init__(%0A        self, url: str, *, table: Optional%5Bstr%5D = None, query: Optional%5Bstr%5D = None%0A    ) -%3E None:%0A        self.query: Union%5Bsqlalchemy.sql.Insert, str%5D%0A        if query is None and table is None:%0A            raise NotImplementedError%0A        if query is not None and table is not None:%0A            raise NotImplementedError%0A        self.engine = sqlalchemy.create_engine(url)%0A        self._type = %22query%22%0A        if table is not None:%0A            self._type = %22table%22%0A            metadata = sqlalchemy.MetaData()%0A            metadata.reflect(self.engine, only=%5Btable%5D)%0A            Base = automap_base(metadata=metadata)%0A            Base.prepare()%0A            self.query = metadata.tables%5Btable%5D.insert()%0A        else:%0A            assert query is not None%0A            self.query = query%0A%0A    def write(%0A        self,%0A        value: Any,%0A        *,%0A        context: Optional%5BContext%5D = None,%0A    ) -%3E None:%0A        j = json.loads(value)%0A        if self._type == %22table%22:%0A            assert isinstance(self.query, sqlalchemy.sql.Insert)%0A            self.engine.execute(self.query.values(j))%0A        else:%0A            assert isinstance(self.query, str)%0A            self.engine.execute(text(self.query), j)%0A

move SQLInputter and SQLOutputter into sql