diff options
author | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2017-01-01 03:50:32 +0100 |
---|---|---|
committer | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2017-01-01 05:23:15 +0100 |
commit | f11e6d82b0f96cf7926634bf09bfe1b4b82d48be (patch) | |
tree | b16533a4f962a30debb4829feb39229075a6e27e /lib/sql.py | |
parent | fad510007905f88f57ceb6f66723e139bfee009e (diff) | |
download | psycopg2-f11e6d82b0f96cf7926634bf09bfe1b4b82d48be.tar.gz |
Added basic sql module implementation
Diffstat (limited to 'lib/sql.py')
-rw-r--r-- | lib/sql.py | 174 |
1 files changed, 174 insertions, 0 deletions
@@ -23,3 +23,177 @@ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. +from psycopg2 import extensions as ext + + +class Composible(object): + """Base class for objects that can be used to compose an SQL string.""" + def as_string(self, conn_or_curs): + raise NotImplementedError + + def __add__(self, other): + if isinstance(other, Composed): + return Composed([self]) + other + if isinstance(other, Composible): + return Composed([self]) + Composed([other]) + else: + return NotImplemented + + +class Composed(Composible): + def __init__(self, seq): + self._seq = [] + for i in seq: + if not isinstance(i, Composible): + raise TypeError( + "Composed elements must be Composible, got %r instead" % i) + self._seq.append(i) + + def __repr__(self): + return "sql.Composed(%r)" % (self.seq,) + + def as_string(self, conn_or_curs): + rv = [] + for i in self._seq: + rv.append(i.as_string(conn_or_curs)) + return ''.join(rv) + + def __add__(self, other): + if isinstance(other, Composed): + return Composed(self._seq + other._seq) + if isinstance(other, Composible): + return Composed(self._seq + [other]) + else: + return NotImplemented + + def __mul__(self, n): + return Composed(self._seq * n) + + def join(self, joiner): + if isinstance(joiner, basestring): + joiner = SQL(joiner) + elif not isinstance(joiner, SQL): + raise TypeError( + "Composed.join() argument must be a string or an SQL") + + if len(self._seq) <= 1: + return self + + it = iter(self._seq) + rv = [it.next()] + for i in it: + rv.append(joiner) + rv.append(i) + + return Composed(rv) + + +class SQL(Composible): + def __init__(self, wrapped): + if not isinstance(wrapped, basestring): + raise TypeError("SQL values must be strings") + self._wrapped = wrapped + + def __repr__(self): + return "sql.SQL(%r)" % (self._wrapped,) + + def as_string(self, conn_or_curs): + return self._wrapped + + def __mul__(self, n): + return Composed([self] * n) + + def join(self, seq): + rv = [] + it = iter(seq) + try: + rv.append(it.next()) + except StopIteration: + pass + else: + for i in it: + rv.append(self) + rv.append(i) + + return Composed(rv) + + +class Identifier(Composible): + def __init__(self, wrapped): + if not isinstance(wrapped, basestring): + raise TypeError("SQL identifiers must be strings") + + self._wrapped = wrapped + + @property + def wrapped(self): + return self._wrapped + + def __repr__(self): + return "sql.Identifier(%r)" % (self._wrapped,) + + def as_string(self, conn_or_curs): + return ext.quote_ident(self._wrapped, conn_or_curs) + + +class Literal(Composible): + def __init__(self, wrapped): + self._wrapped = wrapped + + def __repr__(self): + return "sql.Literal(%r)" % (self._wrapped,) + + def as_string(self, conn_or_curs): + a = ext.adapt(self._wrapped) + if hasattr(a, 'prepare'): + # is it a connection or cursor? + if isinstance(conn_or_curs, ext.connection): + conn = conn_or_curs + elif isinstance(conn_or_curs, ext.cursor): + conn = conn_or_curs.connection + else: + raise TypeError("conn_or_curs must be a connection or a cursor") + + a.prepare(conn) + + return a.getquoted() + + def __mul__(self, n): + return Composed([self] * n) + + +class Placeholder(Composible): + def __init__(self, name=None): + if isinstance(name, basestring): + if ')' in name: + raise ValueError("invalid name: %r" % name) + + elif name is not None: + raise TypeError("expected string or None as name, got %r" % name) + + self._name = name + + def __repr__(self): + return "sql.Placeholder(%r)" % ( + self._name if self._name is not None else '',) + + def __mul__(self, n): + return Composed([self] * n) + + def as_string(self, conn_or_curs): + if self._name is not None: + return "%%(%s)s" % self._name + else: + return "%s" + + +def compose(sql, args=()): + raise NotImplementedError + + +# Alias +PH = Placeholder + +# Literals +NULL = SQL("NULL") +DEFAULT = SQL("DEFAULT") |