summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pgcli/pgcompleter.py20
-rw-r--r--pgcli/pgexecute.py21
-rw-r--r--tests/test_pgexecute.py19
-rw-r--r--tests/test_smart_completion_multiple_schemata.py3
-rw-r--r--tests/test_smart_completion_public_schema_only.py4
5 files changed, 52 insertions, 15 deletions
diff --git a/pgcli/pgcompleter.py b/pgcli/pgcompleter.py
index 6281b08b..8b0b94c3 100644
--- a/pgcli/pgcompleter.py
+++ b/pgcli/pgcompleter.py
@@ -139,17 +139,23 @@ class PGCompleter(Completer):
self.all_completions.add(column)
def extend_functions(self, func_data):
+
+ # func_data is a list of function metadata namedtuples
+ # with fields schema_name, func_name, arg_list, result,
+ # is_aggregate, is_window, is_set_returning
- # func_data is an iterator of (schema_name, function_name)
-
- # dbmetadata['functions']['schema_name']['function_name'] should return
- # function metadata -- right now we're not storing any further metadata
- # so just default to None as a placeholder
+ # dbmetadata['schema_name']['functions']['function_name'] should return
+ # the function metadata namedtuple for the corresponding function
metadata = self.dbmetadata['functions']
for f in func_data:
- schema, func = self.escaped_names(f)
- metadata[schema][func] = None
+ schema, func = self.escaped_names([f.schema_name, f.func_name])
+
+ if func in metadata[schema]:
+ metadata[schema][func].append(f)
+ else:
+ metadata[schema][func] = [f]
+
self.all_completions.add(func)
def extend_datatypes(self, type_data):
diff --git a/pgcli/pgexecute.py b/pgcli/pgexecute.py
index 0c3c356f..9a03f0eb 100644
--- a/pgcli/pgexecute.py
+++ b/pgcli/pgexecute.py
@@ -4,10 +4,12 @@ import psycopg2
import psycopg2.extras
import psycopg2.extensions as ext
import sqlparse
+from collections import namedtuple
from .packages import pgspecial as special
from .encodingutils import unicode2utf8, PY2, utf8tounicode
import click
+
_logger = logging.getLogger(__name__)
# Cast all database input to unicode automatically.
@@ -24,6 +26,10 @@ ext.register_type(ext.new_type((17,), 'BYTEA_TEXT', psycopg2.STRING))
# See http://initd.org/psycopg/articles/2014/07/20/cancelling-postgresql-statements-python/
ext.set_wait_callback(psycopg2.extras.wait_select)
+FunctionMetadata = namedtuple('FunctionMetadata',
+ ['schema_name', 'func_name', 'arg_list', 'result',
+ 'is_aggregate', 'is_window', 'is_set_returning'])
+
def register_json_typecasters(conn, loads_fn):
"""Set the function for converting JSON data for a connection.
@@ -102,14 +108,19 @@ class PGExecute(object):
ORDER BY 1, 2, 3'''
functions_query = '''
- SELECT DISTINCT --multiple dispatch means possible duplicates
- n.nspname schema_name,
- p.proname func_name
+ SELECT n.nspname schema_name,
+ p.proname func_name,
+ pg_catalog.pg_get_function_arguments(p.oid) arg_list,
+ pg_catalog.pg_get_function_result(p.oid) result,
+ p.proisagg is_aggregate,
+ p.proiswindow is_window,
+ p.proretset is_set_returning
FROM pg_catalog.pg_proc p
INNER JOIN pg_catalog.pg_namespace n
ON n.oid = p.pronamespace
ORDER BY 1, 2'''
+
databases_query = """SELECT d.datname as "Name",
pg_catalog.pg_get_userbyid(d.datdba) as "Owner",
pg_catalog.pg_encoding_to_char(d.encoding) as "Encoding",
@@ -346,13 +357,13 @@ class PGExecute(object):
return [x[0] for x in cur.fetchall()]
def functions(self):
- """Yields tuples of (schema_name, function_name)"""
+ """Yields FunctionMetadata named tuples"""
with self.conn.cursor() as cur:
_logger.debug('Functions Query. sql: %r', self.functions_query)
cur.execute(self.functions_query)
for row in cur:
- yield row
+ yield FunctionMetadata(*row)
def datatypes(self):
"""Yields tuples of (schema_name, type_name)"""
diff --git a/tests/test_pgexecute.py b/tests/test_pgexecute.py
index 3f6d4e86..dc289220 100644
--- a/tests/test_pgexecute.py
+++ b/tests/test_pgexecute.py
@@ -4,6 +4,7 @@ import pytest
from pgcli.packages.pgspecial import PGSpecial
from textwrap import dedent
from utils import run, dbtest, requires_json, requires_jsonb
+from pgcli.pgexecute import FunctionMetadata
@dbtest
def test_conn(executor):
@@ -68,8 +69,24 @@ def test_functions_query(executor):
run(executor, '''create function schema1.func2() returns int
language sql as $$select 2$$''')
+ run(executor, '''create function func3()
+ returns table(x int, y int) language sql
+ as $$select 1, 2 from generate_series(1,5)$$;''')
+
+ run(executor, '''create function func4(x int) returns setof int language sql
+ as $$select generate_series(1,5)$$;''')
+
funcs = set(executor.functions())
- assert funcs >= set([('public', 'func1'), ('schema1', 'func2')])
+ assert funcs >= set([
+ FunctionMetadata('public', 'func1', '',
+ 'integer', False, False, False),
+ FunctionMetadata('public', 'func3', '',
+ 'TABLE(x integer, y integer)', False, False, True),
+ FunctionMetadata('public', 'func4', 'x integer',
+ 'SETOF integer', False, False, True),
+ FunctionMetadata('schema1', 'func2', '',
+ 'integer', False, False, False),
+ ])
@dbtest
diff --git a/tests/test_smart_completion_multiple_schemata.py b/tests/test_smart_completion_multiple_schemata.py
index fd8854d6..3a80a42f 100644
--- a/tests/test_smart_completion_multiple_schemata.py
+++ b/tests/test_smart_completion_multiple_schemata.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
import pytest
from prompt_toolkit.completion import Completion
from prompt_toolkit.document import Document
+from pgcli.pgexecute import FunctionMetadata
metadata = {
'tables': {
@@ -40,7 +41,7 @@ def completer():
tables.append((schema, table))
columns.extend([(schema, table, col) for col in cols])
- functions = [(schema, func)
+ functions = [FunctionMetadata(schema, func, '', '', False, False, False)
for schema, funcs in metadata['functions'].items()
for func in funcs]
diff --git a/tests/test_smart_completion_public_schema_only.py b/tests/test_smart_completion_public_schema_only.py
index 2f75069d..e1e2ac17 100644
--- a/tests/test_smart_completion_public_schema_only.py
+++ b/tests/test_smart_completion_public_schema_only.py
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
import pytest
from prompt_toolkit.completion import Completion
from prompt_toolkit.document import Document
+from pgcli.pgexecute import FunctionMetadata
metadata = {
'tables': {
@@ -42,7 +43,8 @@ def completer():
comp.extend_columns(columns, kind='views')
# functions
- functions = [('public', func) for func in metadata['functions']]
+ functions = [FunctionMetadata('public', func, '', '', False, False, False)
+ for func in metadata['functions']]
comp.extend_functions(functions)
# types