From 0cae7e20361dbee41fb8f79d7ee9c763d17d51e1 Mon Sep 17 00:00:00 2001 From: Irina Truong Date: Wed, 2 Jan 2019 16:15:59 -0800 Subject: Remove some functions completions (#982) Remove extension and private functions from completer. --- changelog.rst | 1 + pgcli/packages/parseutils/meta.py | 16 +++++++++------- pgcli/pgcompleter.py | 18 +++++++++++++++--- pgcli/pgexecute.py | 16 ++++++++++++---- tests/parseutils/test_function_metadata.py | 9 ++++++--- tests/test_pgexecute.py | 4 ++-- tests/test_smart_completion_multiple_schemata.py | 20 ++++++++++---------- tests/test_smart_completion_public_schema_only.py | 10 +++++----- 8 files changed, 60 insertions(+), 34 deletions(-) diff --git a/changelog.rst b/changelog.rst index 67256658..a34c95bd 100644 --- a/changelog.rst +++ b/changelog.rst @@ -5,6 +5,7 @@ Features: --------- * Allows passing the ``-u`` flag to specify a username. (Thanks: `Ignacio Campabadal`_) +* Fix for lag in v2 (#979). (Thanks: `Irina Truong`_) Internal: --------- diff --git a/pgcli/packages/parseutils/meta.py b/pgcli/packages/parseutils/meta.py index 16a49676..32dd0aff 100644 --- a/pgcli/packages/parseutils/meta.py +++ b/pgcli/packages/parseutils/meta.py @@ -51,7 +51,8 @@ class FunctionMetadata(object): def __init__( self, schema_name, func_name, arg_names, arg_types, arg_modes, - return_type, is_aggregate, is_window, is_set_returning, arg_defaults + return_type, is_aggregate, is_window, is_set_returning, is_extension, + arg_defaults ): """Class for describing a postgresql function""" @@ -79,6 +80,8 @@ class FunctionMetadata(object): self.is_aggregate = is_aggregate self.is_window = is_window self.is_set_returning = is_set_returning + self.is_extension = bool(is_extension) + self.is_public = (self.schema_name and self.schema_name == 'public') def __eq__(self, other): return (isinstance(other, self.__class__) @@ -89,9 +92,9 @@ class FunctionMetadata(object): def _signature(self): return ( - self.schema_name, self.func_name, self.arg_names, self.arg_types, - self.arg_modes, self.return_type, self.is_aggregate, - self.is_window, self.is_set_returning, self.arg_defaults + self.schema_name, self.func_name, self.arg_names, + self.arg_types, self.arg_modes, self.return_type, self.is_aggregate, + self.is_window, self.is_set_returning, self.is_extension, self.arg_defaults ) def __hash__(self): @@ -102,8 +105,8 @@ class FunctionMetadata(object): ( '%s(schema_name=%r, func_name=%r, arg_names=%r, ' 'arg_types=%r, arg_modes=%r, return_type=%r, is_aggregate=%r, ' - 'is_window=%r, is_set_returning=%r, arg_defaults=%r)' - ) % (self.__class__.__name__,) + self._signature() + 'is_window=%r, is_set_returning=%r, is_extension=%r, arg_defaults=%r)' + ) % ((self.__class__.__name__,) + self._signature()) ) def has_variadic(self): @@ -132,7 +135,6 @@ class FunctionMetadata(object): return [arg(name, typ, num) for num, (name, typ) in enumerate(args)] - def fields(self): """Returns a list of output-field ColumnMetadata namedtuples""" diff --git a/pgcli/pgcompleter.py b/pgcli/pgcompleter.py index 2ec0ac5a..a4c3724d 100644 --- a/pgcli/pgcompleter.py +++ b/pgcli/pgcompleter.py @@ -50,6 +50,7 @@ arg_default_type_strip_regex = re.compile(r'::[\w\.]+(\[\])?$') normalize_ref = lambda ref: ref if ref[0] == '"' else '"' + ref.lower() + '"' + def generate_alias(tbl): """ Generate a table alias, consisting of all upper-case letters in the table name, or, if there are no upper-case letters, the first letter + @@ -636,22 +637,33 @@ class PGCompleter(Completer): return self.find_matches(word_before_cursor, conds, meta='join') def get_function_matches(self, suggestion, word_before_cursor, alias=False): + if suggestion.usage == 'from': # Only suggest functions allowed in FROM clause - def filt(f): return not f.is_aggregate and not f.is_window + + def filt(f): + return (not f.is_aggregate and + not f.is_window and + not f.is_extension and + (f.is_public or f.schema_name == suggestion.schema)) else: alias = False - def filt(f): return True + def filt(f): + return (not f.is_extension and + (f.is_public or f.schema_name == suggestion.schema)) + arg_mode = { 'signature': 'signature', 'special': None, }.get(suggestion.usage, 'call') + # Function overloading means we way have multiple functions of the same # name at this point, so keep unique names only + all_functions = self.populate_functions(suggestion.schema, filt) funcs = set( self._make_cand(f, alias, suggestion, arg_mode) - for f in self.populate_functions(suggestion.schema, filt) + for f in all_functions ) matches = self.find_matches(word_before_cursor, funcs, meta='function') diff --git a/pgcli/pgexecute.py b/pgcli/pgexecute.py index 8bcc5c63..2e9a441f 100644 --- a/pgcli/pgexecute.py +++ b/pgcli/pgexecute.py @@ -629,10 +629,12 @@ class PGExecute(object): p.prokind = 'a' is_aggregate, p.prokind = 'w' is_window, p.proretset is_set_returning, + d.deptype = 'e' is_extension, pg_get_expr(proargdefaults, 0) AS arg_defaults FROM pg_catalog.pg_proc p INNER JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace + LEFT JOIN pg_depend d ON d.objid = p.oid and d.deptype = 'e' WHERE p.prorettype::regtype != 'trigger'::regtype ORDER BY 1, 2 ''' @@ -647,10 +649,12 @@ class PGExecute(object): p.proisagg is_aggregate, p.proiswindow is_window, p.proretset is_set_returning, + d.deptype = 'e' is_extension, pg_get_expr(proargdefaults, 0) AS arg_defaults FROM pg_catalog.pg_proc p INNER JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace + LEFT JOIN pg_depend d ON d.objid = p.oid and d.deptype = 'e' WHERE p.prorettype::regtype != 'trigger'::regtype ORDER BY 1, 2 ''' @@ -665,10 +669,12 @@ class PGExecute(object): p.proisagg is_aggregate, false is_window, p.proretset is_set_returning, + d.deptype = 'e' is_extension, NULL AS arg_defaults FROM pg_catalog.pg_proc p - INNER JOIN pg_catalog.pg_namespace n - ON n.oid = p.pronamespace + INNER JOIN pg_catalog.pg_namespace n + ON n.oid = p.pronamespace + LEFT JOIN pg_depend d ON d.objid = p.oid and d.deptype = 'e' WHERE p.prorettype::regtype != 'trigger'::regtype ORDER BY 1, 2 ''' @@ -683,10 +689,12 @@ class PGExecute(object): p.proisagg is_aggregate, false is_window, p.proretset is_set_returning, + d.deptype = 'e' is_extension, NULL AS arg_defaults FROM pg_catalog.pg_proc p - INNER JOIN pg_catalog.pg_namespace n - ON n.oid = p.pronamespace + INNER JOIN pg_catalog.pg_namespace n + ON n.oid = p.pronamespace + LEFT JOIN pg_depend d ON d.objid = p.oid and d.deptype = 'e' WHERE p.prorettype::regtype != 'trigger'::regtype ORDER BY 1, 2 ''' diff --git a/tests/parseutils/test_function_metadata.py b/tests/parseutils/test_function_metadata.py index 1f9c6930..1d0b72b7 100644 --- a/tests/parseutils/test_function_metadata.py +++ b/tests/parseutils/test_function_metadata.py @@ -3,13 +3,16 @@ from pgcli.packages.parseutils.meta import FunctionMetadata def test_function_metadata_eq(): f1 = FunctionMetadata( - 's', 'f', ['x'], ['integer'], [], 'int', False, False, False, None + 's', 'f', ['x'], ['integer'], [ + ], 'int', False, False, False, False, None ) f2 = FunctionMetadata( - 's', 'f', ['x'], ['integer'], [], 'int', False, False, False, None + 's', 'f', ['x'], ['integer'], [ + ], 'int', False, False, False, False, None ) f3 = FunctionMetadata( - 's', 'g', ['x'], ['integer'], [], 'int', False, False, False, None + 's', 'g', ['x'], ['integer'], [ + ], 'int', False, False, False, False, None ) assert f1 == f2 assert f1 != f3 diff --git a/tests/test_pgexecute.py b/tests/test_pgexecute.py index 559ac5a3..a2340547 100644 --- a/tests/test_pgexecute.py +++ b/tests/test_pgexecute.py @@ -13,11 +13,11 @@ from pgcli.main import PGCli def function_meta_data( func_name, schema_name='public', arg_names=None, arg_types=None, arg_modes=None, return_type=None, is_aggregate=False, is_window=False, - is_set_returning=False, arg_defaults=None + is_set_returning=False, is_extension=False, arg_defaults=None ): return FunctionMetadata( schema_name, func_name, arg_names, arg_types, arg_modes, return_type, - is_aggregate, is_window, is_set_returning, arg_defaults + is_aggregate, is_window, is_set_returning, is_extension, arg_defaults ) @dbtest diff --git a/tests/test_smart_completion_multiple_schemata.py b/tests/test_smart_completion_multiple_schemata.py index fd92c373..c332cf74 100644 --- a/tests/test_smart_completion_multiple_schemata.py +++ b/tests/test_smart_completion_multiple_schemata.py @@ -30,20 +30,20 @@ metadata = { }, 'functions': { 'public': [ - ['func1', [], [], [], '', False, False, False], - ['func2', [], [], [], '', False, False, False]], + ['func1', [], [], [], '', False, False, False, False], + ['func2', [], [], [], '', False, False, False, False]], 'custom': [ - ['func3', [], [], [], '', False, False, False], + ['func3', [], [], [], '', False, False, False, False], ['set_returning_func', ['x'], ['integer'], ['o'], - 'integer', False, False, True]], + 'integer', False, False, True, False]], 'Custom': [ - ['func4', [], [], [], '', False, False, False]], + ['func4', [], [], [], '', False, False, False, False]], 'blog': [ ['extract_entry_symbols', ['_entryid', 'symbol'], - ['integer', 'text'], ['i', 'o'], '', False, False, True], + ['integer', 'text'], ['i', 'o'], '', False, False, True, False], ['enter_entry', ['_title', '_text', 'entryid'], ['text', 'text', 'integer'], ['i', 'i', 'o'], - '', False, False, False]], + '', False, False, False, False]], }, 'datatypes': { 'public': ['typ1', 'typ2'], @@ -579,7 +579,7 @@ def test_all_schema_objects(completer): result = result_set(completer, text) assert result >= set( [table(x) for x in ('orders', '"select"', 'custom.shipments')] - + [function(x+'()') for x in ('func2', 'custom.func3')] + + [function(x + '()') for x in ('func2',)] ) @@ -589,7 +589,7 @@ def test_all_schema_objects_with_casing(completer): result = result_set(completer, text) assert result >= set( [table(x) for x in ('Orders', '"select"', 'CUSTOM.shipments')] - + [function(x+'()') for x in ('func2', 'CUSTOM.func3')] + + [function(x + '()') for x in ('func2',)] ) @@ -599,7 +599,7 @@ def test_all_schema_objects_with_aliases(completer): result = result_set(completer, text) assert result >= set( [table(x) for x in ('orders o', '"select" s', 'custom.shipments s')] - + [function(x) for x in ('func2() f', 'custom.func3() f')] + + [function(x) for x in ('func2() f',)] ) diff --git a/tests/test_smart_completion_public_schema_only.py b/tests/test_smart_completion_public_schema_only.py index 3ccac9e5..0b8fbcc4 100644 --- a/tests/test_smart_completion_public_schema_only.py +++ b/tests/test_smart_completion_public_schema_only.py @@ -17,12 +17,12 @@ metadata = { 'functions': ['function'], }, 'functions': [ - ['custom_fun', [], [], [], '', False, False, False], - ['_custom_fun', [], [], [], '', False, False, False], - ['custom_func1', [], [], [], '', False, False, False], - ['custom_func2', [], [], [], '', False, False, False], + ['custom_fun', [], [], [], '', False, False, False, False], + ['_custom_fun', [], [], [], '', False, False, False, False], + ['custom_func1', [], [], [], '', False, False, False, False], + ['custom_func2', [], [], [], '', False, False, False, False], ['set_returning_func', ['x', 'y'], ['integer', 'integer'], - ['b', 'b'], '', False, False, True]], + ['b', 'b'], '', False, False, True, False]], 'datatypes': ['custom_type1', 'custom_type2'], 'foreignkeys': [ ('public', 'users', 'id', 'public', 'users', 'parentid'), -- cgit v1.2.3