Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add support for Hstore.

Support for Hstore had to be added because before the
adapter and typecaster for for dict-hstore conversions
can be registered the OID's for the hstore types need
to be manually fetched and fed to `psycopg2.extras.register_hstore`.
  • Loading branch information...
commit 16f52185330a8ac44312416f1fe71eed72bfc745 1 parent 92940db
Frank Smit authored
Showing with 39 additions and 11 deletions.
  1. +16 −0 examples/gen_example.py
  2. +23 −11 momoko/connection.py
16 examples/gen_example.py
View
@@ -43,6 +43,7 @@ def get(self):
<ul>
<li><a href="/mogrify">Mogrify</a></li>
<li><a href="/query">A single query</a></li>
+ <li><a href="/hstore">An hstore query</a></li>
<li><a href="/transaction">A transaction</a></li>
<li><a href="/multi_query">Multiple queries executed with gen.Task</a></li>
<li><a href="/callback_and_wait">Multiple queries executed with gen.Callback and gen.Wait</a></li>
@@ -77,6 +78,19 @@ def get(self):
self.finish()
+class HstoreQueryHandler(BaseHandler):
+ @tornado.web.asynchronous
+ @gen.engine
+ def get(self):
+ try:
+ cursor = yield momoko.Op(self.db.execute, "SELECT 'a=>b, c=>d'::hstore;")
+ self.write('Query results: %s<br>' % cursor.fetchall())
+ except Exception as error:
+ self.write(str(error))
+
+ self.finish()
+
+
class MultiQueryHandler(BaseHandler):
@tornado.web.asynchronous
@gen.engine
@@ -150,6 +164,7 @@ def main():
(r'/', OverviewHandler),
(r'/mogrify', MogrifyHandler),
(r'/query', SingleQueryHandler),
+ (r'/hstore', HstoreQueryHandler),
(r'/transaction', TransactionHandler),
(r'/multi_query', MultiQueryHandler),
(r'/callback_and_wait', CallbackWaitHandler),
@@ -157,6 +172,7 @@ def main():
application.db = momoko.Pool(
dsn=dsn,
+ register_hstore=True,
minconn=1,
maxconn=10,
cleanup_timeout=10
34 momoko/connection.py
View
@@ -14,6 +14,7 @@
from collections import deque, defaultdict
import psycopg2
+from psycopg2.extras import register_hstore
from psycopg2.extensions import (connection as base_connection, cursor as base_cursor,
POLL_OK, POLL_READ, POLL_WRITE, POLL_ERROR, TRANSACTION_STATUS_IDLE)
@@ -31,6 +32,19 @@ def _dummy_callback(cursor, error):
pass
+# Fetch the hstore and hstore array OID's and register adapter and typecaster
+# for dict-hstore conversions. Fetching the OID's must be done manually, because
+# ``register_hstore`` can not use an asynchronous connection to do that.
+def _register_hstore(connection):
+ def psycopg2_register_hstore(cursor, error):
+ oid, array_oid = cursor.fetchone()
+ register_hstore(None, True, False, oid, array_oid)
+
+ connection.execute(
+ "SELECT 'hstore'::regtype::oid, 'hstore[]'::regtype::oid",
+ callback=psycopg2_register_hstore)
+
+
class Pool:
"""
Asynchronous connection pool.
@@ -41,6 +55,7 @@ class Pool:
``connection_factory`` parameters. These are used by the connection pool when
a new connection is created.
+ :param boolean register_hstore: Register adapter and typecaster for ``dict-hstore`` conversions.
:param integer minconn: Amount of connections created upon initialization. Defaults to ``1``.
:param integer maxconn: Maximum amount of connections allowed by the pool. Defaults to ``5``.
:param integer cleanup_timeout:
@@ -55,6 +70,7 @@ class Pool:
def __init__(self,
dsn,
connection_factory=None,
+ register_hstore=False,
minconn=1,
maxconn=5,
cleanup_timeout=10,
@@ -71,19 +87,15 @@ def __init__(self,
self._pool = []
# Create connections
- if callback:
- self._after_connect = self.minconn
-
- def after_connect(_):
- self._after_connect -= 1
- if self._after_connect == 0:
+ def after_pool_creation(n, connection):
+ if n == self.minconn-1:
+ if register_hstore:
+ _register_hstore(connection)
+ if callback:
callback()
- for i in range(self.minconn):
- self.new(after_connect)
- else:
- for i in range(self.minconn):
- self.new()
+ for i in range(self.minconn):
+ self.new(partial(after_pool_creation, i))
# Create a periodic callback that tries to close inactive connections
self._cleaner = None
Please sign in to comment.
Something went wrong with that request. Please try again.