2011-12-22 19:03:54 +01:00
|
|
|
import logging
|
|
|
|
|
from datetime import datetime
|
2012-01-04 00:15:10 +01:00
|
|
|
from collections import defaultdict
|
2012-07-23 15:27:42 +02:00
|
|
|
from threading import RLock
|
2011-12-22 19:03:54 +01:00
|
|
|
|
|
|
|
|
from sqlalchemy import create_engine
|
2012-01-04 00:15:10 +01:00
|
|
|
from sqlalchemy import Integer, UnicodeText, Float, DateTime, Boolean
|
2012-03-16 22:56:52 +01:00
|
|
|
from sqlalchemy.schema import Table, MetaData, Column, Index
|
2011-12-22 19:03:54 +01:00
|
|
|
from sqlalchemy.sql import and_, expression
|
|
|
|
|
from migrate.versioning.util import construct_engine
|
|
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
2012-07-23 15:27:42 +02:00
|
|
|
lock = RLock()
|
2011-12-22 19:03:54 +01:00
|
|
|
|
|
|
|
|
def connect(url):
|
|
|
|
|
""" Create an engine for the given database URL. """
|
2012-01-21 21:38:31 +01:00
|
|
|
kw = {}
|
2012-08-12 11:54:32 +02:00
|
|
|
if url.startswith('postgres'):
|
|
|
|
|
#kw['pool_size'] = 5
|
|
|
|
|
from sqlalchemy.pool import NullPool
|
|
|
|
|
kw['poolclass'] = NullPool
|
2012-01-21 21:38:31 +01:00
|
|
|
engine = create_engine(url, **kw)
|
2011-12-22 19:03:54 +01:00
|
|
|
engine = construct_engine(engine)
|
|
|
|
|
meta = MetaData()
|
|
|
|
|
meta.bind = engine
|
|
|
|
|
engine._metadata = meta
|
2013-02-27 23:10:05 +01:00
|
|
|
engine._tables = dict()
|
|
|
|
|
engine._indexes = dict()
|
2011-12-22 19:03:54 +01:00
|
|
|
return engine
|
|
|
|
|
|
|
|
|
|
def create_table(engine, table_name):
|
2012-07-23 15:27:42 +02:00
|
|
|
with lock:
|
|
|
|
|
log.debug("Creating table: %s on %r" % (table_name, engine))
|
|
|
|
|
table = Table(table_name, engine._metadata)
|
|
|
|
|
col = Column('id', Integer, primary_key=True)
|
|
|
|
|
table.append_column(col)
|
|
|
|
|
table.create(engine)
|
2013-02-27 23:10:05 +01:00
|
|
|
engine._tables[table_name] = table
|
2012-07-23 15:27:42 +02:00
|
|
|
return table
|
2011-12-22 19:03:54 +01:00
|
|
|
|
|
|
|
|
def load_table(engine, table_name):
|
2012-07-23 15:27:42 +02:00
|
|
|
with lock:
|
|
|
|
|
log.debug("Loading table: %s on %r" % (table_name, engine))
|
|
|
|
|
table = Table(table_name, engine._metadata, autoload=True)
|
2013-02-27 23:10:05 +01:00
|
|
|
engine._tables[table_name] = table
|
2012-07-23 15:27:42 +02:00
|
|
|
return table
|
2011-12-22 19:03:54 +01:00
|
|
|
|
|
|
|
|
def get_table(engine, table_name):
|
2013-03-30 22:28:32 +01:00
|
|
|
if isinstance(table_name, Table):
|
|
|
|
|
return table_name
|
|
|
|
|
|
2012-02-09 14:48:45 +01:00
|
|
|
# Accept Connection objects here
|
|
|
|
|
if hasattr(engine, 'engine'):
|
|
|
|
|
engine = engine.engine
|
2012-07-23 15:27:42 +02:00
|
|
|
|
|
|
|
|
with lock:
|
2013-02-27 23:10:05 +01:00
|
|
|
if table_name in engine._tables:
|
|
|
|
|
return engine._tables[table_name]
|
2012-07-23 15:27:42 +02:00
|
|
|
if engine.has_table(table_name):
|
|
|
|
|
return load_table(engine, table_name)
|
|
|
|
|
else:
|
|
|
|
|
return create_table(engine, table_name)
|
2011-12-22 19:03:54 +01:00
|
|
|
|
2012-02-09 14:48:45 +01:00
|
|
|
def drop_table(engine, table_name):
|
|
|
|
|
# Accept Connection objects here
|
|
|
|
|
if hasattr(engine, 'engine'):
|
|
|
|
|
engine = engine.engine
|
2012-07-23 15:27:42 +02:00
|
|
|
|
|
|
|
|
with lock:
|
2013-02-27 23:10:05 +01:00
|
|
|
if table_name in engine._tables:
|
|
|
|
|
table = engine._tables[table_name]
|
2012-07-23 15:27:42 +02:00
|
|
|
elif engine.has_table(table_name):
|
|
|
|
|
table = Table(table_name, engine._metadata)
|
|
|
|
|
else:
|
|
|
|
|
return
|
|
|
|
|
table.drop(engine)
|
2013-02-27 23:10:05 +01:00
|
|
|
engine._tables.pop(table_name, None)
|
2012-02-09 14:48:45 +01:00
|
|
|
|
2011-12-22 19:03:54 +01:00
|
|
|
def _guess_type(sample):
|
2012-01-04 00:15:10 +01:00
|
|
|
if isinstance(sample, bool):
|
|
|
|
|
return Boolean
|
|
|
|
|
elif isinstance(sample, int):
|
2011-12-22 19:03:54 +01:00
|
|
|
return Integer
|
|
|
|
|
elif isinstance(sample, float):
|
|
|
|
|
return Float
|
|
|
|
|
elif isinstance(sample, datetime):
|
|
|
|
|
return DateTime
|
|
|
|
|
return UnicodeText
|
|
|
|
|
|
|
|
|
|
def _ensure_columns(engine, table, row, types={}):
|
|
|
|
|
columns = set(row.keys()) - set(table.columns.keys())
|
|
|
|
|
for column in columns:
|
|
|
|
|
if column in types:
|
|
|
|
|
_type = types[column]
|
|
|
|
|
else:
|
|
|
|
|
_type = _guess_type(row[column])
|
|
|
|
|
log.debug("Creating column: %s (%s) on %r" % (column,
|
|
|
|
|
_type, table.name))
|
|
|
|
|
create_column(engine, table, column, _type)
|
|
|
|
|
|
|
|
|
|
def _args_to_clause(table, args):
|
|
|
|
|
clauses = []
|
|
|
|
|
for k, v in args.items():
|
|
|
|
|
clauses.append(table.c[k] == v)
|
|
|
|
|
return and_(*clauses)
|
|
|
|
|
|
|
|
|
|
def create_column(engine, table, name, type):
|
2013-03-30 22:28:32 +01:00
|
|
|
table = get_table(engine, table)
|
2012-07-23 15:27:42 +02:00
|
|
|
with lock:
|
|
|
|
|
if name not in table.columns.keys():
|
|
|
|
|
col = Column(name, type)
|
|
|
|
|
col.create(table, connection=engine)
|
2011-12-22 19:03:54 +01:00
|
|
|
|
2012-03-16 22:56:52 +01:00
|
|
|
def create_index(engine, table, columns, name=None):
|
2013-03-30 22:28:32 +01:00
|
|
|
table = get_table(engine, table)
|
2012-07-23 15:27:42 +02:00
|
|
|
with lock:
|
|
|
|
|
if not name:
|
|
|
|
|
sig = abs(hash('||'.join(columns)))
|
|
|
|
|
name = 'ix_%s_%s' % (table.name, sig)
|
2013-02-27 23:10:05 +01:00
|
|
|
if name in engine._indexes:
|
|
|
|
|
return engine._indexes[name]
|
2012-07-23 15:27:42 +02:00
|
|
|
try:
|
|
|
|
|
columns = [table.c[c] for c in columns]
|
|
|
|
|
idx = Index(name, *columns)
|
|
|
|
|
idx.create(engine)
|
|
|
|
|
except:
|
|
|
|
|
idx = None
|
2013-02-27 23:10:05 +01:00
|
|
|
engine._indexes[name] = idx
|
2012-07-23 15:27:42 +02:00
|
|
|
return idx
|
2012-03-16 22:56:52 +01:00
|
|
|
|