Skip to content

Commit 7d6cf06

Browse files
committed
dbmetadata: Now case insensitive
Rather than nested dict, example {"table": {"AdventureWorks2017": {"Person": {"Address": {}}, ...}, ...}, ...} to represent AdventureWorks2017.Person.Address Now: {"table": {"adventureworks2017": ("AdventureWorks2017": {"person": ("Person", {...}), ... )}. That is to say, whereas previously we had [cased]: {}, each entry is now [lowercase]: ([cased], {...}).
1 parent 74117e8 commit 7d6cf06

2 files changed

Lines changed: 60 additions & 33 deletions

File tree

odbcli/completion/mssqlcompleter.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ def extend_casing(self, words):
172172
self.casing = dict((word.lower(), word) for word in words)
173173

174174
def extend_functions(self, func_data):
175+
""" OG: Currently not used
176+
"""
175177

176178
# func_data is a list of function metadata namedtuples
177179

@@ -195,6 +197,8 @@ def extend_functions(self, func_data):
195197
self._refresh_arg_list_cache()
196198

197199
def _refresh_arg_list_cache(self):
200+
""" OG: Currently not used
201+
"""
198202
# We keep a cache of {function_usage:{function_metadata: function_arg_list_string}}
199203
# This is used when suggesting functions, to avoid the latency that would result
200204
# if we'd recalculate the arg lists each time we suggest functions (in
@@ -212,6 +216,8 @@ def _refresh_arg_list_cache(self):
212216
}
213217

214218
def extend_foreignkeys(self, fk_data):
219+
""" OG: Currently not used
220+
"""
215221

216222
# fk_data is a list of ForeignKey namedtuples, with fields
217223
# parentschema, childschema, parenttable, childtable,
@@ -237,6 +243,8 @@ def extend_foreignkeys(self, fk_data):
237243
parcolmeta.foreignkeys.append((fk))
238244

239245
def extend_datatypes(self, type_data):
246+
""" OG: Currently not used
247+
"""
240248

241249
# dbmetadata['datatypes'][schema_name][type_name] should store type
242250
# metadata, such as composite type field names. Currently, we're not
@@ -576,7 +584,7 @@ def get_join_matches(self, suggestion, word_before_cursor):
576584

577585
def get_join_condition_matches(self, suggestion, word_before_cursor):
578586
col = namedtuple('col', 'schema tbl col')
579-
tbls = self.populate_scoped_cols(suggestion.table_refs).items
587+
tbls = self.populate_scoped_cols2(suggestion.table_refs).items
580588
cols = [(t, c) for t, cs in tbls() for c in cs]
581589
try:
582590
lref = (suggestion.parent or suggestion.table_refs[-1]).ref
@@ -630,8 +638,9 @@ def list_dict(pairs): # Turns [(a, b), (a, c)] into {a: [b, c]}
630638
# TODO: Need to account for suggestion.catalog
631639
def get_function_matches(
632640
self, suggestion, word_before_cursor, alias=False):
633-
634-
# OG: hack early exit, for now
641+
""" OG: currently not used / hacked to exit early
642+
"""
643+
# OG: hack early exit
635644
return []
636645
# We'll have to do away with this right? How can we possibly know this
637646
if suggestion.usage == 'from':
@@ -668,8 +677,6 @@ def filt(_):
668677

669678
def get_schema_matches(self, suggestion, word_before_cursor):
670679
conn = self.active_conn
671-
metadata = conn.dbmetadata.data
672-
submeta = metadata['table']
673680
if suggestion.parent:
674681
catalog_u = self.unescape_name(suggestion.parent)
675682
else:
@@ -830,7 +837,6 @@ def get_alias_matches(self, suggestion, word_before_cursor):
830837

831838
def get_database_matches(self, _, word_before_cursor):
832839
conn = self.active_conn
833-
metadata = conn.dbmetadata.data
834840
catalogs_e = conn.dbmetadata.get_catalogs()
835841
if catalogs_e is None and (conn.connected()):
836842
catalogs_e = self.escape_names(conn.list_catalogs())
@@ -879,6 +885,8 @@ def get_special_matches(self, _, word_before_cursor):
879885
return self.find_matches(word_before_cursor, cmds, mode='strict')
880886

881887
def get_datatype_matches(self, suggestion, word_before_cursor):
888+
""" OG: Currently not used
889+
"""
882890
# suggest custom datatypes
883891
types = self.populate_schema_objects(suggestion.schema, 'datatypes')
884892
types = [self._make_cand(t, False, suggestion) for t in types]
@@ -909,7 +917,7 @@ def get_datatype_matches(self, suggestion, word_before_cursor):
909917
Database: get_database_matches,
910918
Keyword: get_keyword_matches,
911919
Special: get_special_matches,
912-
Datatype: get_datatype_matches,
920+
# Datatype: get_datatype_matches,
913921
# NamedQuery: get_namedquery_matches,
914922
Path: get_path_matches,
915923
}
@@ -1027,7 +1035,8 @@ def addcols(catalog, schema, rel, alias, reltype, cols):
10271035
return columns
10281036

10291037
def _get_schemas(self, obj_typ, schema):
1030-
"""Returns a list of schemas from which to suggest objects.
1038+
""" OG: Currently not used
1039+
Returns a list of schemas from which to suggest objects.
10311040
10321041
:param schema is the schema qualification input by the user (if any)
10331042
@@ -1044,7 +1053,8 @@ def _maybe_schema(self, schema, parent):
10441053
return None if parent or schema in self.search_path else schema
10451054

10461055
def populate_schema_objects(self, schema, obj_type):
1047-
"""Returns a list of SchemaObjects representing tables or views.
1056+
""" OG: Currently not used
1057+
Returns a list of SchemaObjects representing tables or views.
10481058
10491059
:param schema is the schema qualification input by the user (if any)
10501060
@@ -1070,8 +1080,6 @@ def populate_objects(self, catalog, schema, obj_type):
10701080
ret = []
10711081
obj_names = []
10721082
conn = self.active_conn
1073-
metadata = conn.dbmetadata.data
1074-
submeta = metadata[obj_type]
10751083
self.logger.debug("populate_objects(%s): Called for %s.%s",
10761084
obj_type, catalog, schema)
10771085
if catalog is None and schema is None:
@@ -1144,7 +1152,8 @@ def populate_objects(self, catalog, schema, obj_type):
11441152
return ret
11451153

11461154
def populate_functions(self, schema, filter_func):
1147-
"""Returns a list of function SchemaObjects.
1155+
""" OG: currently not used.
1156+
Returns a list of function SchemaObjects.
11481157
11491158
:param filter_func is a function that accepts a FunctionMetadata
11501159
namedtuple and returns a boolean indicating whether that

odbcli/dbmetadata.py

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,65 +10,81 @@ def extend_catalogs(self, names: list) -> None:
1010
with self._lock:
1111
for metadata in self._dbmetadata.values():
1212
for catalog in names:
13-
metadata[catalog] = {}
13+
metadata[catalog.lower()] = (catalog, {})
1414
return
1515

16-
def get_catalogs(self, obj_type: str = "table") -> list:
16+
def get_catalogs(self, obj_type: str = "table", cased: bool = True) -> list:
1717
""" Retrieve catalogs as the keys for _dbmetadata[obj_type]
1818
If no keys are found it returns None.
1919
"""
2020
with self._lock:
21-
res = self._dbmetadata[obj_type].keys()
21+
if cased:
22+
res = [casedkey for casedkey, mappedvalue in self._dbmetadata[obj_type].values()]
23+
else:
24+
res = list(self._dbmetadata[obj_type].keys())
25+
2226

2327
if len(res) == 0:
2428
return None
2529

26-
return list(res)
30+
return res
2731

2832
def extend_schemas(self, catalog, names: list) -> None:
2933
""" This method will force/create [catalog] dictionary
3034
in the event that len(names) > 0, and overwrite if
3135
anything was there to begin with.
3236
"""
37+
catlower = catalog.lower()
38+
cat_cased = catalog
3339
if len(names):
3440
with self._lock:
3541
for metadata in self._dbmetadata.values():
36-
metadata[catalog] = {}
42+
# Preserve casing if an entry already there
43+
if catlower in metadata.keys() and len(metadata[catlower]):
44+
cat_cased = metadata[catlower][0]
45+
metadata[catlower] = (cat_cased, {})
3746
for schema in names:
38-
metadata[catalog][schema] = {}
47+
metadata[catlower][1][schema.lower()] = (schema, {})
3948
return
4049

41-
def get_schemas(self, catalog: str, obj_type: str = "table") -> list:
50+
def get_schemas(self, catalog: str, obj_type: str = "table", cased: bool = True) -> list:
4251
""" Retrieve schemas as the keys for _dbmetadata[obj_type][catalog]
4352
If catalog is not part of the _dbmetadata[obj_type] keys will return
4453
None.
4554
"""
4655

47-
cats = self.get_catalogs(obj_type = obj_type)
48-
if cats is None or catalog not in cats:
56+
catlower = catalog.lower()
57+
cats = self.get_catalogs(obj_type = obj_type, cased = False)
58+
if cats is None or catlower not in cats:
4959
return None
5060

5161
with self._lock:
52-
res = self._dbmetadata[obj_type][catalog].keys()
62+
if cased:
63+
res = [casedkey for casedkey, mappedvalue in self._dbmetadata[obj_type][catlower][1].values()]
64+
else:
65+
res = list(self._dbmetadata[obj_type][catlower][1].keys())
5366

54-
return list(res)
67+
68+
return res
5569

5670
def extend_objects(self, catalog, schema, names: list, obj_type: str) -> None:
71+
catlower = catalog.lower()
72+
schlower = schema.lower()
5773
if len(names):
5874
with self._lock:
59-
for metadata in self._dbmetadata.values():
75+
for otype in self._dbmetadata.keys():
6076
# Loop over tables, views, functions
61-
if catalog not in metadata.keys():
62-
metadata[catalog] = {}
63-
if schema not in metadata[catalog].keys():
64-
metadata[catalog][schema] = {}
77+
if catlower not in self._dbmetadata[otype].keys():
78+
self._dbmetadata[otype][catlower] = (catalog, {})
79+
if schlower not in self._dbmetadata[otype][catlower][1].keys():
80+
self._dbmetadata[otype][catlower][1][schlower] = (schema, {})
6581
for obj in names:
66-
self._dbmetadata[obj_type][catalog][schema][obj] = {}
82+
self._dbmetadata[obj_type][catlower][1][schlower][1][obj.lower()] = (obj, {})
6783
# If we passed nothing then take out that element entirely out
6884
# of the dict
6985
else:
7086
with self._lock:
71-
del self._dbmetadata[obj_type][catalog][schema]
87+
del self._dbmetadata[obj_type][catlower][1][schlower]
7288

7389
return
7490

@@ -78,12 +94,14 @@ def get_objects(self, catalog: str, schema: str, obj_type: str = "table") -> lis
7894
not one of the keys in _dbmetadata[obj_type][catalog] will return None
7995
"""
8096

81-
schemas = self.get_schemas(catalog = catalog, obj_type = obj_type)
82-
if schemas is None or schema not in schemas:
97+
catlower = catalog.lower()
98+
schlower = schema.lower()
99+
schemas = self.get_schemas(catalog = catalog, obj_type = obj_type, cased = False)
100+
if schemas is None or schlower not in schemas:
83101
return None
84102

85103
with self._lock:
86-
res = self._dbmetadata[obj_type][catalog][schema].keys()
104+
res = [casedkey for casedkey, mappedvalue in self._dbmetadata[obj_type][catlower][1][schlower][1].values()]
87105

88106
return list(res)
89107

0 commit comments

Comments
 (0)