diff options
author | Roman Podolyaka <roman.podolyaka@gmail.com> | 2013-06-09 19:07:00 +0300 |
---|---|---|
committer | Roman Podolyaka <roman.podolyaka@gmail.com> | 2013-06-09 23:49:55 +0300 |
commit | c69fe4acf8929856735e5d90adb7f6b6d5ebcd46 (patch) | |
tree | e193633bdf96f536d826122a1186d067dbc9890f /lib/sqlalchemy/dialects | |
parent | f65ddee93a7143924b417e1c988802f10d0c7b11 (diff) | |
download | sqlalchemy-pr/4.tar.gz |
Add basic support of unique constraints reflectionpr/4
Inspection API already supports reflection of table
indexes information and those also include unique
constraints (at least for PostgreSQL and MySQL).
But it could be actually useful to distinguish between
indexes and plain unique constraints (though both are
implemented in the same way internally in RDBMS).
This change adds a new method to Inspection API - get_unique_constraints()
and implements it for SQLite, PostgreSQL and MySQL dialects.
Diffstat (limited to 'lib/sqlalchemy/dialects')
-rw-r--r-- | lib/sqlalchemy/dialects/mysql/base.py | 15 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/postgresql/base.py | 30 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/sqlite/base.py | 20 |
3 files changed, 65 insertions, 0 deletions
diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index 9d856e271..2642b5fdc 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -2212,6 +2212,21 @@ class MySQLDialect(default.DefaultDialect): return indexes @reflection.cache + def get_unique_constraints(self, connection, table_name, + schema=None, **kw): + parsed_state = self._parsed_state_or_create( + connection, table_name, schema, **kw) + + return [ + { + 'name': key['name'], + 'column_names': [col[0] for col in key['columns']] + } + for key in parsed_state.keys + if key['type'] == 'UNIQUE' + ] + + @reflection.cache def get_view_definition(self, connection, view_name, schema=None, **kw): charset = self._connection_charset diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py index 00d0acc2c..0810e0384 100644 --- a/lib/sqlalchemy/dialects/postgresql/base.py +++ b/lib/sqlalchemy/dialects/postgresql/base.py @@ -1950,6 +1950,36 @@ class PGDialect(default.DefaultDialect): index_d['unique'] = unique return indexes + @reflection.cache + def get_unique_constraints(self, connection, table_name, + schema=None, **kw): + table_oid = self.get_table_oid(connection, table_name, schema, + info_cache=kw.get('info_cache')) + + UNIQUE_SQL = """ + SELECT + cons.conname as name, + ARRAY_AGG(a.attname) as column_names + FROM + pg_catalog.pg_constraint cons + left outer join pg_attribute a + on cons.conrelid = a.attrelid and a.attnum = ANY(cons.conkey) + WHERE + cons.conrelid = :table_oid AND + cons.contype = 'u' + GROUP BY + cons.conname + """ + + t = sql.text(UNIQUE_SQL, + typemap={'column_names': ARRAY(sqltypes.Unicode)}) + c = connection.execute(t, table_oid=table_oid) + + return [ + {'name': row.name, 'column_names': row.column_names} + for row in c.fetchall() + ] + def _load_enums(self, connection): if not self.supports_native_enum: return {} diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py index c7e09b164..3e2a158a0 100644 --- a/lib/sqlalchemy/dialects/sqlite/base.py +++ b/lib/sqlalchemy/dialects/sqlite/base.py @@ -917,6 +917,26 @@ class SQLiteDialect(default.DefaultDialect): cols.append(row[2]) return indexes + @reflection.cache + def get_unique_constraints(self, connection, table_name, + schema=None, **kw): + UNIQUE_SQL = """ + SELECT sql + FROM + sqlite_master + WHERE + type='table' AND + name=:table_name + """ + c = connection.execute(UNIQUE_SQL, table_name=table_name) + table_data = c.fetchone()[0] + + UNIQUE_PATTERN = 'CONSTRAINT (\w+) UNIQUE \(([^\)]+)\)' + return [ + {'name': name, 'column_names': [c.strip() for c in cols.split(',')]} + for name, cols in re.findall(UNIQUE_PATTERN, table_data) + ] + def _pragma_cursor(cursor): """work around SQLite issue whereby cursor.description |