sql-testing-tools 0.2.11__tar.gz → 0.2.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql_testing_tools
3
- Version: 0.2.11
3
+ Version: 0.2.12
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Requires-Dist: sqlparse>=0.5.1
@@ -135,6 +135,10 @@ res = checkEquality()
135
135
 
136
136
  ### Changelog
137
137
 
138
+ ##### V 0.2.12
139
+ - fixed bug when having only one colum selected
140
+ - fixed bug with nested conditions
141
+
138
142
  ##### V 0.2.11
139
143
  - fixed irrelevant equality order if both sides aren't literals
140
144
 
@@ -123,6 +123,10 @@ res = checkEquality()
123
123
 
124
124
  ### Changelog
125
125
 
126
+ ##### V 0.2.12
127
+ - fixed bug when having only one colum selected
128
+ - fixed bug with nested conditions
129
+
126
130
  ##### V 0.2.11
127
131
  - fixed irrelevant equality order if both sides aren't literals
128
132
 
@@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
6
6
 
7
7
  setup(
8
8
  name='sql_testing_tools',
9
- version='0.2.11',
9
+ version='0.2.12',
10
10
  packages=find_packages(),
11
11
  install_requires=[
12
12
  'sqlparse>=0.5.1',
@@ -26,22 +26,23 @@ dbMap = {
26
26
  }
27
27
 
28
28
  __db=""
29
+ dbiu = 'dbiu.'
29
30
 
30
31
  def setDBName(database):
31
32
  global __db
32
33
 
33
- if isinstance(database, str) and database.startswith("dbiu."):
34
- dbVersion = dbMap.get(database)
34
+ if isinstance(database, str) and database.startswith(dbiu):
35
+ db_version = dbMap.get(database)
35
36
  elif isinstance(database, int):
36
- dbVersion = database
37
- database = "dbiu."+str(database)
37
+ db_version = database
38
+ database = dbiu+str(database)
38
39
  elif isinstance(database, str):
39
- dbVersion = None
40
+ db_version = None
40
41
  else:
41
42
  raise Exception("Invalid database selected")
42
43
 
43
- if(dbVersion is not None):
44
- os.system('pip install dbiu_databases=='+str(dbVersion))
44
+ if(db_version is not None):
45
+ os.system('pip install dbiu_databases=='+str(db_version))
45
46
  try:
46
47
  import dbiu_databases
47
48
  except ImportError:
@@ -51,7 +52,7 @@ def setDBName(database):
51
52
 
52
53
 
53
54
  def run(sql: str):
54
- if __db.startswith("dbiu.") and not __db.endswith(".db"):
55
+ if __db.startswith(dbiu) and not __db.endswith(".db"):
55
56
  with importlib.resources.path('dbiu_databases', "base.db") as db_path:
56
57
  return __run(sql, db_path)
57
58
  else:
@@ -64,7 +65,7 @@ def __run(sql: str, db: str):
64
65
  con.commit()
65
66
  return cur
66
67
 
67
- def runFromFile(path: str):
68
+ def runFromFile(path: str, limit: int = None):
68
69
  sql = getSQLFromFile(path)
69
70
  if not sql:
70
71
  raise Exception("\nSQL-Datei ist leer. Aufgabe wurde noch nicht bearbeitet.")
@@ -79,15 +80,19 @@ def runFromFile(path: str):
79
80
  raise Exception(f"\n\nSyntax-Fehler in der SQL-Abfrage:\n{str(e)}")
80
81
 
81
82
  headers = [h[0] for h in res.description] if res.description else []
82
- rows = res.fetchall() if res else []
83
+ if limit:
84
+ rows = res.fetchmany(limit)
85
+ else:
86
+ rows = res.fetchall() if res else []
83
87
 
84
88
  return headers, rows
85
89
 
86
90
 
87
- def runAndGetStringTable_fromFile(path: str, count: int = 5, maxLineLength: int = 85):
91
+ def runAndGetStringTable_fromFile(path: str, count: int = 5, max_line_length: int = 85):
88
92
  try:
89
- headers, rows = runFromFile(path)
90
- resultCount = len(rows)
93
+ limit = 1000
94
+ headers, rows = runFromFile(path, limit)
95
+ result_count = len(rows)
91
96
  rows = rows[:count]
92
97
  s = ""
93
98
 
@@ -104,52 +109,51 @@ def runAndGetStringTable_fromFile(path: str, count: int = 5, maxLineLength: int
104
109
  matrix[col].append(rows[row][col])
105
110
 
106
111
  for col in range(len(matrix)):
107
- maxLength = max([len(str(x)) for x in matrix[col]])
112
+ max_length = max([len(str(x)) for x in matrix[col]])
108
113
 
109
114
  for row in range(0, len(matrix[col])):
110
- matrix[col][row] = str(matrix[col][row]).ljust(maxLength)
115
+ matrix[col][row] = str(matrix[col][row]).ljust(max_length)
111
116
 
112
- normalizedRows = []
117
+ normalized_rows = []
113
118
  spacing = " "
114
- spacingLength = len(spacing) * (len(matrix[0]) - 1)
119
+ spacing_length = len(spacing) * (len(matrix[0]) - 1)
115
120
 
116
- lineLength = sum([len(x[0]) for x in matrix]) + spacingLength
121
+ line_length = sum([len(x[0]) for x in matrix]) + spacing_length
117
122
 
118
123
 
119
124
 
120
- if lineLength > maxLineLength:
121
- valLength = lineLength - spacingLength
122
- maxColLength = int(maxLineLength/len(matrix))
125
+ if line_length > max_line_length:
126
+ max_col_length = int(max_line_length/len(matrix))
123
127
 
124
128
  for col in range(len(matrix)):
125
129
  for row in range(0, len(matrix[col])):
126
- cutContent = len(matrix[col][row].strip()) > maxColLength
127
- if cutContent:
128
- matrix[col][row] = matrix[col][row][:maxColLength-2] + ".."
130
+ cut_content = len(matrix[col][row].strip()) > max_col_length
131
+ if cut_content:
132
+ matrix[col][row] = matrix[col][row][:max_col_length-2] + ".."
129
133
  else:
130
- matrix[col][row] = matrix[col][row][:maxColLength]
134
+ matrix[col][row] = matrix[col][row][:max_col_length]
131
135
 
132
136
 
133
137
  for row in range(min(count+1, len(matrix[0]))):
134
- normalizedRows.append(spacing.join([str(matrix[col][row]) for col in range(len(matrix))]))
135
- normalizedRows.insert(1, len(normalizedRows[0])*"-")
138
+ normalized_rows.append(spacing.join([str(matrix[col][row]) for col in range(len(matrix))]))
139
+ normalized_rows.insert(1, len(normalized_rows[0])*"-")
136
140
 
137
- s = "\n".join(normalizedRows[:count+2])
138
- s += "\n" + normalizedRows[1]
141
+ s = "\n".join(normalized_rows[:count+2])
142
+ s += "\n" + normalized_rows[1]
139
143
 
140
- if (resultCount > count):
141
- s += "\n... " + str(resultCount - count) + " weitere Zeilen"
144
+ if (result_count > count):
145
+ if result_count == limit:
146
+ s += "\n... mehr als " + str(limit) + " Zeilen"
147
+ else:
148
+ s += "\n... " + str(result_count - count) + " weitere Zeilen"
142
149
  else:
143
150
  s += "\n... keine weiteren Zeilen"
144
-
145
- #longestLineInS = 85 # max([len(x.replace("\t", " ")) for x in s.split("\n")])
146
-
147
- #s = "-" * longestLineInS + "\n" + s + "\n" + "-" * longestLineInS
148
151
  s = "\n\nDiese Meldung sagt nichts über die Korrektheit der Abgabe aus!\nDie ersten " + str(
149
152
  count) + " Zeilen des Ergebnisses der SQL-Abfrage:\n\n" + s
150
153
 
151
154
  return s.replace("None", "NULL")
152
155
  except Exception as ex:
156
+ print(ex)
153
157
  raise ex
154
158
 
155
159
  def getSQLFromFile(path: str):
@@ -15,26 +15,37 @@ from sqlparse.tokens import Keyword, DML, Name, Wildcard
15
15
  sql = ""
16
16
  sol = ""
17
17
  bd = None
18
+ kw_sel = 'SELECT'
19
+ kw_frm = 'FROM'
20
+ kw_by = ' BY'
21
+ kw_grp = 'GROUP' + kw_by
22
+ kw_ord = 'ORDER' + kw_by
23
+ kw_whr = 'WHERE'
24
+ kw_lim = 'LIMIT'
25
+ kw_hav = 'HAVING'
26
+ semcol = ';'
18
27
 
19
- def setup(sqlPath,solPath):
28
+
29
+
30
+ def setup(sql_path,sol_path):
20
31
  global sql, sol, bd
21
32
  if(bd == None):
22
33
  bd = Ba.getTableDict()
23
- if(sqlPath and sqlPath != ""):
24
- sql = normalizeSQLQuery(Ba.getSQLFromFile(sqlPath), bd)
25
- if(solPath and solPath != ""):
26
- sol = normalizeSQLQuery(Ba.getSQLFromFile(solPath), bd)
34
+ if(sql_path and sql_path != ""):
35
+ sql = normalizeSQLQuery(Ba.getSQLFromFile(sql_path), bd)
36
+ if(sol_path and sol_path != ""):
37
+ sol = normalizeSQLQuery(Ba.getSQLFromFile(sol_path), bd)
27
38
  if(sql=='' or sol==''):
28
- raise Exception("\n\nSQL-Datei ist leer. Aufgabe wurde noch nicht bearbeitet.")
39
+ raise AssertionError("\n\nSQL-Datei ist leer. Aufgabe wurde noch nicht bearbeitet.")
29
40
 
30
41
 
31
- def normalizeSQLQuery(query, baseDict):
42
+ def normalizeSQLQuery(query, base_dict):
32
43
  try:
33
- query = query.replace("\"", "'")
44
+ query = query.replace("\"", "'").replace("\n", " ").replace("\r", " ").replace("\t", " ").replace(" ", " ").strip()
34
45
  parsed = sqlparse.parse(query)[0]
35
46
  parsed.tokens = [token for token in parsed.tokens if not token.is_whitespace]
36
47
  except Exception as e:
37
- raise Exception(f"\nSyntax-Fehler in der SQL-Abfrage.")
48
+ raise AssertionError(f"\nFehler beim Parsen der SQL-Abfrage: {str(e)}")
38
49
 
39
50
  formatted_query = []
40
51
  alias_map = {}
@@ -43,16 +54,15 @@ def normalizeSQLQuery(query, baseDict):
43
54
  for token in parsed.tokens:
44
55
  if token.is_whitespace:
45
56
  continue
46
- elif token.ttype is Keyword and token.value.upper() == 'FROM':
47
- formatted_query.append('FROM')
48
- pass
49
- elif isinstance(token, Identifier) and formatted_query and formatted_query[-1] == 'FROM':
57
+ elif token.ttype is Keyword and token.value.upper() == kw_frm:
58
+ formatted_query.append(kw_frm)
59
+ elif isinstance(token, Identifier) and formatted_query and formatted_query[-1] == kw_frm:
50
60
  il = IdentifierList([token])
51
- formatted_query.append(Tp._from(il, alias_map, baseDict))
52
- Tp._from(il, alias_map, baseDict)
53
- elif isinstance(token, IdentifierList) and formatted_query and formatted_query[-1] == 'FROM':
54
- formatted_query.append(Tp._from(token, alias_map, baseDict))
55
- Tp._from(token, alias_map, baseDict)
61
+ formatted_query.append(Tp._from(il, alias_map, base_dict))
62
+ Tp._from(il, alias_map, base_dict)
63
+ elif isinstance(token, IdentifierList) and formatted_query and formatted_query[-1] == kw_frm:
64
+ formatted_query.append(Tp._from(token, alias_map, base_dict))
65
+ Tp._from(token, alias_map, base_dict)
56
66
 
57
67
  formatted_query = []
58
68
 
@@ -60,40 +70,40 @@ def normalizeSQLQuery(query, baseDict):
60
70
  for token in parsed.tokens:
61
71
  if token.is_whitespace:
62
72
  continue
63
- elif token.ttype is DML and token.value.upper() == 'SELECT':
64
- formatted_query.append('SELECT')
65
- elif token.ttype is Keyword and token.value.upper() == 'FROM':
66
- formatted_query.append('FROM')
67
- elif token.ttype is Keyword and token.value.upper() == 'GROUP BY':
68
- formatted_query.append('GROUP BY')
69
- elif token.ttype is Keyword and token.value.upper() == 'ORDER BY':
70
- formatted_query.append('ORDER BY')
71
- elif token.ttype is Keyword and token.value.upper() == 'LIMIT':
72
- formatted_query.append('LIMIT')
73
- elif (isinstance(token, IdentifierList) or isinstance(token, Identifier)) and formatted_query and formatted_query[-1] == 'FROM':
74
- formatted_query.append(Tp._from(token, alias_map, baseDict))
75
- elif (isinstance(token, IdentifierList) or isinstance(token, Identifier)) and formatted_query and formatted_query[-1] == 'GROUP BY':
76
- formatted_query.append(Tp._groupby(token, alias_map, baseDict))
77
- elif (isinstance(token, IdentifierList) or isinstance(token, Identifier)) and formatted_query and formatted_query[-1] == 'ORDER BY':
78
- formatted_query.append(Tp._orderby(token, alias_map, baseDict))
73
+ elif token.ttype is DML and token.value.upper() == kw_sel:
74
+ formatted_query.append(kw_sel)
75
+ elif token.ttype is Keyword and token.value.upper() == kw_frm:
76
+ formatted_query.append(kw_frm)
77
+ elif token.ttype is Keyword and token.value.upper() == kw_grp:
78
+ formatted_query.append(kw_grp)
79
+ elif token.ttype is Keyword and token.value.upper() == kw_ord:
80
+ formatted_query.append(kw_ord)
81
+ elif token.ttype is Keyword and token.value.upper() == kw_lim:
82
+ formatted_query.append(kw_lim)
83
+ elif (isinstance(token, IdentifierList) or isinstance(token, Identifier)) and formatted_query and formatted_query[-1] == kw_frm:
84
+ formatted_query.append(Tp._from(token, alias_map, base_dict))
85
+ elif (isinstance(token, IdentifierList) or isinstance(token, Identifier)) and formatted_query and formatted_query[-1] == kw_grp:
86
+ formatted_query.append(Tp._groupby(token, alias_map, base_dict))
87
+ elif (isinstance(token, IdentifierList) or isinstance(token, Identifier)) and formatted_query and formatted_query[-1] == kw_ord:
88
+ formatted_query.append(Tp._orderby(token, alias_map, base_dict))
79
89
  elif isinstance(token, Where):
80
- formatted_query.append('WHERE')
81
- formatted_query.append(Tp._where(token, alias_map, baseDict))
82
- elif formatted_query and formatted_query[-1] == 'SELECT' and (isinstance(token, IdentifierList) or isinstance(token, Function) or isinstance(token, Identifier)):
90
+ formatted_query.append(kw_whr)
91
+ formatted_query.append(Tp._where(token, alias_map, base_dict))
92
+ elif formatted_query and formatted_query[-1] == kw_sel and (isinstance(token, IdentifierList) or isinstance(token, Function) or isinstance(token, Identifier)):
83
93
  if isinstance(token, Function):
84
94
  token = IdentifierList([token])
85
- formatted_query.append(Tp._select(token, alias_map, baseDict))
86
- elif formatted_query and formatted_query[-1] == 'LIMIT':
95
+ formatted_query.append(Tp._select(token, alias_map, base_dict))
96
+ elif formatted_query and formatted_query[-1] == kw_lim:
87
97
  formatted_query.append(Tp._limit(token))
88
98
  else:
89
99
  formatted_query.append(str(token))
90
100
 
91
101
  return " ".join(formatted_query)
92
102
 
93
- def findTableForColumn(data_dict, target_value, relevantTables):
103
+ def find_table_for_column(data_dict, target_value, relevant_tables):
94
104
  l = []
95
105
  for key, value_list in data_dict.items():
96
- if key.lower() in relevantTables:
106
+ if key.lower() in relevant_tables:
97
107
  for sublist in value_list:
98
108
  if sublist and sublist[0].lower() == target_value.lower():
99
109
  l.append(key)
@@ -104,8 +114,8 @@ def findTableForColumn(data_dict, target_value, relevantTables):
104
114
  l.append(key)
105
115
  return l
106
116
 
107
- def getTableScheme(table_name: str, tableDict: dict):
108
- tab = tableDict[table_name]
117
+ def getTableScheme(table_name: str, table_dict: dict):
118
+ tab = table_dict[table_name]
109
119
 
110
120
  # Format the schema
111
121
  schema = "(" + ",".join([f"{col[0]}:{col[1]}" for col in tab]) + ")"
@@ -118,18 +128,18 @@ def getCosetteKeyFromFile():
118
128
  except FileNotFoundError:
119
129
  return "NOKEY"
120
130
 
121
- def buildAndSendCosetteRequest(baseDict, sql, sol):
131
+ def buildAndSendCosetteRequest(base_dict, sql, sol):
122
132
 
123
133
  err = ""
124
- for i in range(2):
134
+ for _ in range(2):
125
135
  try:
126
- apiKey=getCosetteKeyFromFile()
136
+ api_key=getCosetteKeyFromFile()
127
137
 
128
138
 
129
139
  schema = ""
130
- for tab in baseDict.keys():
131
- schema += f"schema sch{tab}{getTableScheme(tab, baseDict)};\n"
132
- for tab in baseDict.keys():
140
+ for tab in base_dict.keys():
141
+ schema += f"schema sch{tab}{getTableScheme(tab, base_dict)};\n"
142
+ for tab in base_dict.keys():
133
143
  schema += f"table {tab}(sch{tab});\n"
134
144
 
135
145
  q1 = "query q1\n`"+sql+"`;\n"
@@ -138,29 +148,25 @@ def buildAndSendCosetteRequest(baseDict, sql, sol):
138
148
  cosette = "-- random Kommentar\n" + schema + q1 + q2 + "verify q1 q2;\n"
139
149
  print(cosette)
140
150
 
141
- r = requests.post("https://demo.cosette.cs.washington.edu/solve",data={"api_key": apiKey, "query": cosette}, verify=False)
151
+ r = requests.post("https://demo.cosette.cs.washington.edu/solve",data={"api_key": api_key, "query": cosette}, verify=False)
142
152
 
143
153
  print(r.text)
144
154
  return (r.json()['result'],r.text)
145
- #return r.json()['result']
146
-
147
155
  except Exception as e:
148
156
  err = str(e)
149
157
  return ("ERR", err)
150
158
 
151
159
 
152
- def checkKeywords(startWord:str, endWords:list):
153
- #global sql,sol
160
+ def check_keywords(start_word:str, end_words:list):
161
+ start_word = start_word.lower()
154
162
 
155
- startWord = startWord.lower()
156
-
157
- if(startWord not in sol.lower() and startWord not in sql.lower()):
163
+ if(start_word not in sol.lower() and start_word not in sql.lower()):
158
164
  return ""
159
165
 
160
- if(startWord in sql.lower()):
161
- start = sql.lower().find(startWord) + len(startWord)
166
+ if(start_word in sql.lower()):
167
+ start = sql.lower().find(start_word) + len(start_word)
162
168
  end = -1
163
- for kw in endWords:
169
+ for kw in end_words:
164
170
  index = sql.lower().find(kw.lower(), start)
165
171
  if -1 < index < end or end == -1:
166
172
  end = index
@@ -168,12 +174,11 @@ def checkKeywords(startWord:str, endWords:list):
168
174
  end = len(sql)
169
175
 
170
176
  submission = str.strip(sql[start:end])
171
- #print("'"+submission+"'")
172
177
 
173
- start = sol.lower().find(startWord) + len(startWord)
178
+ start = sol.lower().find(start_word) + len(start_word)
174
179
  end = -1
175
180
 
176
- for kw in endWords:
181
+ for kw in end_words:
177
182
  index = sol.lower().find(kw.lower(), start)
178
183
  if -1 < index < end or end == -1:
179
184
  end = index
@@ -184,45 +189,54 @@ def checkKeywords(startWord:str, endWords:list):
184
189
 
185
190
  if submission == solution:
186
191
  return ""
187
- return "Der '"+startWord+"' Teil der SQL-Abfrage ist nicht korrekt (oder nicht automatisch überprüfbar)."
192
+ return "Der '"+start_word+"' Teil der SQL-Abfrage ist nicht korrekt (oder nicht automatisch überprüfbar)."
188
193
 
189
194
 
190
- def checkColumns(sqlPath="", solPath=""):
191
- #global sql,sol
192
- setup(sqlPath, solPath)
193
- return checkKeywords("SELECT ", ["FROM", "WHERE", "GROUP BY", "ORDER BY", "LIMIT", ";", "HAVING"])
195
+ def checkColumns(sql_path="", sol_path=""):
196
+ setup(sql_path, sol_path)
197
+ return check_keywords(kw_sel+" ", [kw_frm, kw_whr, kw_grp, kw_ord, kw_lim, semcol, kw_hav])
194
198
 
195
199
 
196
- def checkTables(sqlPath="", solPath=""):
197
- #global sql,sol
198
- setup(sqlPath, solPath)
199
- return checkKeywords("FROM ", ["SELECT", "WHERE", "GROUP BY", "ORDER BY", "LIMIT", ";", "HAVING"])
200
+ def checkTables(sql_path="", sol_path=""):
201
+ setup(sql_path, sol_path)
202
+ return check_keywords(kw_frm+" ", [kw_sel, kw_whr, kw_grp, kw_ord, kw_lim, semcol, kw_hav])
200
203
 
201
204
 
202
- def checkCondition(sqlPath="", solPath=""):
203
- #global sql,sol
204
- setup(sqlPath, solPath)
205
- return checkKeywords("WHERE ", ["SELECT", "FROM", "GROUP BY", "ORDER BY", "LIMIT", ";", "HAVING"])
205
+ def checkCondition(sql_path="", sol_path=""):
206
+ setup(sql_path, sol_path)
207
+ return check_keywords(kw_whr+" ", [kw_sel, kw_frm, kw_grp, kw_ord, kw_lim, semcol, kw_hav])
206
208
 
207
209
 
208
- def checkOrder(sqlPath="", solPath=""):
209
- #global sql,sol
210
- setup(sqlPath, solPath)
211
- return checkKeywords("ORDER BY ", ["SELECT", "WHERE", "GROUP BY", "FROM", "LIMIT", ";", "HAVING"])
210
+ def checkOrder(sql_path="", sol_path=""):
211
+ setup(sql_path, sol_path)
212
+ return check_keywords(kw_ord+" ", [kw_sel, kw_whr, kw_grp, kw_frm, kw_lim, semcol, kw_hav])
212
213
 
213
214
 
214
- def checkGroup(sqlPath="", solPath=""):
215
- #global sql, sol
216
- setup(sqlPath, solPath)
217
- return checkKeywords("GROUP BY ", ["SELECT", "WHERE", "FROM BY", "ORDER BY", "LIMIT", ";", "HAVING"])
215
+ def checkGroup(sql_path="", sol_path=""):
216
+ setup(sql_path, sol_path)
217
+ return check_keywords(kw_grp+" ", [kw_sel, kw_whr, kw_grp, kw_ord, kw_lim, semcol, kw_hav])
218
218
 
219
219
 
220
- def checkEquality(sqlPath="", solPath=""):
221
- #global sql, sol
222
- setup(sqlPath, solPath)
220
+ def checkEquality(sql_path="", sol_path=""):
221
+ setup(sql_path, sol_path)
223
222
 
224
223
  if sql == sol:
225
224
  return ""
225
+
226
+
227
+ sql_build_fail = ""
228
+ sol_build_fail = ""
229
+ try:
230
+ Ba.runAndGetStringTable_fromFile(sql_path)
231
+ except Exception as e:
232
+ sql_build_fail = str(e)
233
+ try:
234
+ Ba.runAndGetStringTable_fromFile(sol_path)
235
+ except Exception as e:
236
+ sol_build_fail = str(e)
237
+
238
+ if(sql_build_fail != "" or sol_build_fail != ""):
239
+ return "\n\nFehler beim Ausführen der Abfrage. Vermutlich enthält die Abfrage Syntaxfehler:\n" + sql_build_fail + "\n" + sol_build_fail
226
240
 
227
241
  result = buildAndSendCosetteRequest(bd, sql, sol)
228
242
 
@@ -11,12 +11,12 @@ except ImportError:
11
11
  #####################################
12
12
  #####################################
13
13
 
14
- def _identifier(identifier, alias_map, baseDict: dict):
14
+ def _identifier(identifier, alias_map, base_dict: dict):
15
15
  if isinstance(identifier, Identifier):
16
16
  if identifier.get_real_name() and identifier.get_parent_name() and identifier.get_parent_name().lower() in alias_map.keys():
17
17
  return f"{alias_map[identifier.get_parent_name().lower()].lower()}.{identifier.get_real_name().lower()}"
18
18
  elif identifier.get_real_name():
19
- tables = He.findTableForColumn(baseDict, identifier.get_real_name(), alias_map.keys())
19
+ tables = He.find_table_for_column(base_dict, identifier.get_real_name(), alias_map.keys())
20
20
  if len(tables) == 1:
21
21
  alias_map[tables[0].lower()] = tables[0]
22
22
  return f"{tables[0].lower()}.{identifier.get_real_name().lower()}"
@@ -29,24 +29,29 @@ def _identifier(identifier, alias_map, baseDict: dict):
29
29
  #####################################
30
30
 
31
31
 
32
- def _select(select, alias_map, baseDict: dict, insideFunction=False):
32
+ def _select(select, alias_map, base_dict: dict, insideFunction=False):
33
33
  select_tokens = []
34
+ if isinstance(select, Identifier):
35
+ if insideFunction:
36
+ select_tokens.append(_identifier(select, alias_map, base_dict).lower())
37
+ else:
38
+ select_tokens.append(f"{_identifier(select, alias_map, base_dict).lower()} as {select.get_real_name().lower()}")
34
39
  for token in select.tokens:
35
40
  if isinstance(token, IdentifierList):
36
41
  for identifier in token.get_identifiers():
37
- select_tokens.append(f"{_identifier(identifier, alias_map, baseDict).lower()} as {identifier.get_real_name().lower()}")
42
+ select_tokens.append(f"{_identifier(identifier, alias_map, base_dict).lower()} as {identifier.get_real_name().lower()}")
38
43
  elif isinstance(token, Identifier):
39
44
  if insideFunction:
40
- select_tokens.append(_identifier(token, alias_map, baseDict).lower())
45
+ select_tokens.append(_identifier(token, alias_map, base_dict).lower())
41
46
  else:
42
- select_tokens.append(f"{_identifier(token, alias_map, baseDict).lower()} as {token.get_real_name().lower()}")
47
+ select_tokens.append(f"{_identifier(token, alias_map, base_dict).lower()} as {token.get_real_name().lower()}")
43
48
  elif isinstance(token, Function):
44
- #select_tokens.append(f"{token.get_name().lower()}({_identifier(token.get_parameters(), alias_map, baseDict).lower()})")
49
+ #select_tokens.append(f"{token.get_name().lower()}({_identifier(token.get_parameters(), alias_map, base_dict).lower()})")
45
50
  for par in token.tokens:
46
51
  if isinstance(par, Identifier):
47
52
  select_tokens.append(par.get_name().lower()+"(")
48
53
  if isinstance(par, Parenthesis):
49
- select_tokens[-1] += _select(par, alias_map, baseDict, True)+") as funcResult"
54
+ select_tokens[-1] += _select(par, alias_map, base_dict, True)+") as funcResult"
50
55
  elif token.ttype is Wildcard:
51
56
  select_tokens.append("*")
52
57
  else:
@@ -59,7 +64,7 @@ def _select(select, alias_map, baseDict: dict, insideFunction=False):
59
64
  #####################################
60
65
 
61
66
 
62
- def _from(from_, alias_map, baseDict: dict):
67
+ def _from(from_, alias_map, base_dict: dict):
63
68
  from_tokens = []
64
69
  if hasattr(from_, 'tokens'):
65
70
  for token in from_.tokens:
@@ -83,32 +88,32 @@ def _from(from_, alias_map, baseDict: dict):
83
88
  #####################################
84
89
 
85
90
 
86
- def _groupby(groupby_, alias_map, baseDict: dict):
91
+ def _groupby(groupby_, alias_map, base_dict: dict):
87
92
  groupby_tokens = []
88
93
  if(isinstance(groupby_, Identifier)):
89
- groupby_tokens.append(_identifier(groupby_, alias_map, baseDict).lower())
94
+ groupby_tokens.append(_identifier(groupby_, alias_map, base_dict).lower())
90
95
  elif isinstance(groupby_, IdentifierList):
91
96
  for identifier in groupby_.get_identifiers():
92
- groupby_tokens.append(_identifier(identifier, alias_map, baseDict).lower())
97
+ groupby_tokens.append(_identifier(identifier, alias_map, base_dict).lower())
93
98
  groupby_tokens.sort()
94
99
  return ",".join(groupby_tokens)
95
100
 
96
- def _orderby(orderby_, alias_map, baseDict: dict):
101
+ def _orderby(orderby_, alias_map, base_dict: dict):
97
102
  orderby_tokens = []
98
103
  if isinstance(orderby_, Identifier):
99
104
  if len(orderby_.tokens) > 0 and orderby_.tokens[-1].ttype==Keyword.Order:
100
105
  for tok in orderby_.tokens:
101
106
  if isinstance(tok, Identifier):
102
- orderby_tokens.append(_identifier(tok, alias_map, baseDict).lower())
107
+ orderby_tokens.append(_identifier(tok, alias_map, base_dict).lower())
103
108
  if tok.ttype==Keyword.Order:
104
109
  orderby_tokens[-1] += (" "+tok.value)
105
110
  else:
106
- orderby_tokens.append(_identifier(orderby_, alias_map, baseDict).lower())
111
+ orderby_tokens.append(_identifier(orderby_, alias_map, base_dict).lower())
107
112
  orderby_tokens[-1] += " ASC"
108
113
  elif isinstance(orderby_, IdentifierList):
109
114
  for tok in orderby_.tokens:
110
115
  if isinstance(tok, Identifier):
111
- orderby_tokens.append(_identifier(tok, alias_map, baseDict).lower())
116
+ orderby_tokens.append(_identifier(tok, alias_map, base_dict).lower())
112
117
  #elif isinstance(orderby_, Order):
113
118
  # pass
114
119
  # orderby_tokens.sort()
@@ -133,7 +138,7 @@ def replace_not_with_parenthesis(where_tokens):
133
138
  i += 1
134
139
  return new_tokens
135
140
 
136
- def _condition(token, alias_map, baseDict: dict):
141
+ def _condition(token, alias_map, base_dict: dict):
137
142
  left, operator, right = [t for t in token.tokens if not t.is_whitespace]
138
143
 
139
144
  flipAllowed = True
@@ -158,8 +163,8 @@ def _condition(token, alias_map, baseDict: dict):
158
163
  rightLiteral = True
159
164
  flipAllowed = False
160
165
 
161
- left = _identifier(left, alias_map, baseDict)
162
- right = _identifier(right, alias_map, baseDict)
166
+ left = _identifier(left, alias_map, base_dict)
167
+ right = _identifier(right, alias_map, base_dict)
163
168
 
164
169
  if operator.value.strip() in ("!=", "<>"):
165
170
  return f"(NOT {left.lower()} LIKE {right})"
@@ -195,7 +200,7 @@ def is_value(token):
195
200
  #####################################
196
201
 
197
202
 
198
- def _paranthesis(parenthesis, alias_map, baseDict: dict):
203
+ def _paranthesis(parenthesis, alias_map, base_dict: dict):
199
204
  toks = []
200
205
 
201
206
  bracketsRequired = True
@@ -206,10 +211,10 @@ def _paranthesis(parenthesis, alias_map, baseDict: dict):
206
211
 
207
212
 
208
213
  if(and_count==1 and or_count == 0):
209
- val = _2element_par(parenthesis, alias_map, baseDict, "AND")
214
+ val = _2element_par(parenthesis, alias_map, base_dict, "AND")
210
215
  return val
211
216
  elif(and_count==0 and or_count == 1):
212
- val = _2element_par(parenthesis, alias_map, baseDict, "OR")
217
+ val = _2element_par(parenthesis, alias_map, base_dict, "OR")
213
218
  return val
214
219
 
215
220
 
@@ -219,9 +224,9 @@ def _paranthesis(parenthesis, alias_map, baseDict: dict):
219
224
 
220
225
  for token in parenthesis.tokens:
221
226
  if isinstance(token, Comparison):
222
- toks.append(_condition(token, alias_map, baseDict))
227
+ toks.append(_condition(token, alias_map, base_dict))
223
228
  elif isinstance(token, Parenthesis):
224
- toks.append(_paranthesis(token, alias_map, baseDict))
229
+ toks.append(_paranthesis(token, alias_map, base_dict))
225
230
 
226
231
  elif token.ttype is Keyword: #AND,OR
227
232
  if token.value == "AND":
@@ -239,14 +244,14 @@ def _paranthesis(parenthesis, alias_map, baseDict: dict):
239
244
  return " ".join(toks)
240
245
 
241
246
 
242
- def _2element_par(parenthesis, alias_map, baseDict: dict, keyword):
247
+ def _2element_par(parenthesis, alias_map, base_dict: dict, keyword):
243
248
  toks = []
244
249
 
245
250
  for token in parenthesis.tokens:
246
251
  if isinstance(token, Comparison):
247
- toks.append(_condition(token, alias_map, baseDict))
252
+ toks.append(_condition(token, alias_map, base_dict))
248
253
  elif isinstance(token, Parenthesis):
249
- toks.append(_paranthesis(token, alias_map, baseDict))
254
+ toks.append(_paranthesis(token, alias_map, base_dict))
250
255
  toks = toks.sort()
251
256
  fill = (" "+keyword+" ")
252
257
  return fill.join(toks)
@@ -263,13 +268,8 @@ def find_index_of_keyword(tokens, keyword):
263
268
  return -1 # Wenn kein AND-Token gefunden wird
264
269
 
265
270
 
266
- def _where(where, alias_map, baseDict: dict):
267
- conditions = []
268
- current_condition = []
269
-
270
-
271
-
272
- isParanthesis = isinstance(where, Parenthesis)
271
+ def _where(where, alias_map, base_dict: dict):
272
+ is_paranthesis = isinstance(where, Parenthesis)
273
273
 
274
274
  where_tokens = [token for token in where.tokens if (token.ttype is not Whitespace and token.ttype is not Newline) and token.value != "WHERE"]
275
275
  where_tokens = replace_not_with_parenthesis(where_tokens)
@@ -282,11 +282,11 @@ def _where(where, alias_map, baseDict: dict):
282
282
 
283
283
  # No AND / OR
284
284
  if and_count + or_count == 0:
285
- return _where_simpleCondition(where, alias_map, baseDict)
285
+ return _where_simpleCondition(where, alias_map, base_dict)
286
286
 
287
287
  # only ANDs / only ORs
288
288
  elif and_count == 0 or or_count == 0:
289
- return _where_sameStrengthKeywords(where_tokens, alias_map, baseDict, " AND " if and_count > 0 else " OR ")
289
+ return _where_sameStrengthKeywords(where_tokens, alias_map, base_dict, " AND " if and_count > 0 else " OR ")
290
290
 
291
291
  # ANDs and ORs
292
292
 
@@ -298,96 +298,56 @@ def _where(where, alias_map, baseDict: dict):
298
298
  # two conditions on top level
299
299
  if top_and_count + top_or_count == 1:
300
300
  keyword = " AND " if top_and_count == 1 else " OR "
301
- return _where_twoConditionsOnTopLevel(where, alias_map, baseDict, keyword, isParanthesis)
301
+ return _where_twoConditionsOnTopLevel(where, alias_map, base_dict, keyword, is_paranthesis)
302
302
  else:
303
- where_tokens = _where_addBracketsAroundAND(where, alias_map, baseDict)
304
- return _where(Where(where_tokens), alias_map, baseDict)
303
+ where_tokens = _where_addBracketsAroundAND(where, alias_map, base_dict)
304
+ return _where(Where(where_tokens), alias_map, base_dict)
305
305
 
306
- def _where_addBracketsAroundAND(where, alias_map, baseDict: dict):
306
+ def _where_addBracketsAroundAND(where, alias_map, base_dict: dict):
307
307
  index = find_index_of_keyword(where.tokens, "AND")
308
308
  par = Parenthesis(where.tokens[index-2:index+3])
309
309
  where_tokens = where.tokens[:index-2] + [par] + where.tokens[index+3:]
310
310
  return where_tokens
311
311
 
312
312
 
313
-
314
- # for token in where.tokens:
315
- # if token.is_whitespace or (token.ttype is Keyword and token.value.upper() == "WHERE"):
316
- # continue
317
-
318
- # if token.ttype is Keyword and token.value.upper() in ('AND', 'OR'):
319
- # if current_condition:
320
- # conditions.append(''.join(str(t) for t in current_condition).strip())
321
- # current_condition = []
322
- # conditions.append(token.value.upper())
323
- # else:
324
- # current_condition.append(token)
325
-
326
- # if current_condition:
327
- # conditions.append(''.join(str(t) for t in current_condition).strip())
328
-
329
- # sorted_conditions = []
330
- # current_group = []
331
- # last_connector = ""
332
-
333
- # if "OR" not in conditions:
334
- # for condition in conditions:
335
- # if condition == 'AND':
336
- # pass
337
- # else:
338
- # current_group.append(condition)
339
-
340
- # if current_group:
341
- # sorted_conditions.extend(sorted(current_group))
342
-
343
- # return " AND ".join(sorted_conditions)
344
- # else:
345
- # return " ".join(conditions)
346
-
347
- # where_index = query.upper().find('WHERE')
348
-
349
- # normalized_query = query[:where_index + 5] + ' ' + ' '.join(sorted_conditions)
350
-
351
-
352
-
353
- def _where_simpleCondition(where_tokens, alias_map, baseDict: dict):
313
+ def _where_simpleCondition(where_tokens, alias_map, base_dict: dict):
354
314
  cond = []
355
315
  for tok in where_tokens:
356
316
  if tok.ttype == Keyword and tok.value.upper() == "NOT":
357
317
  cond.append("NOT ")
358
318
  if isinstance(tok, Comparison):
359
- cond.append(_condition(tok, alias_map, baseDict))
319
+ cond.append(_condition(tok, alias_map, base_dict))
360
320
  elif isinstance(tok, Parenthesis):
361
321
  for _tok in tok.tokens:
362
322
  if isinstance(_tok, Comparison):
363
- cond.append(_condition(_tok, alias_map, baseDict))
323
+ cond.append(_condition(_tok, alias_map, base_dict))
364
324
  elif isinstance(_tok, Parenthesis):
365
325
  tok = _tok
366
326
  return "".join(cond)
367
327
 
368
- def _where_sameStrengthKeywords(where_tokens, alias_map, baseDict: dict, keyword: str):
328
+ def _where_sameStrengthKeywords(where_tokens, alias_map, base_dict: dict, keyword: str):
369
329
  cond = []
370
330
  for tok in where_tokens:
371
331
  if isinstance(tok, Comparison):
372
- cond.append(_where_simpleCondition([tok], alias_map, baseDict))
332
+ cond.append(_where_simpleCondition([tok], alias_map, base_dict))
373
333
  elif isinstance(tok, Parenthesis):
374
- isNot = tok.tokens[0].ttype == Keyword and tok.tokens[0].value.upper() == "NOT"
375
- cond.append(("(" if isNot else "") + _where(tok, alias_map, baseDict) + (")" if isNot else ""))
334
+ is_not = tok.tokens[0].ttype == Keyword and tok.tokens[0].value.upper() == "NOT"
335
+ cond.append(("(" if is_not else "") + _where(tok, alias_map, base_dict) + (")" if is_not else ""))
376
336
  cond.sort()
377
337
  return keyword.join(cond)
378
338
 
379
- def _where_twoConditionsOnTopLevel(where, alias_map, baseDict: dict, keyword, isParanthesis):
339
+ def _where_twoConditionsOnTopLevel(where, alias_map, base_dict: dict, keyword, is_paranthesis):
380
340
  current_condition = []
381
341
  for tok in where.tokens:
382
342
  if isinstance(tok, Comparison):
383
- current_condition.append(_condition(tok, alias_map, baseDict))
343
+ current_condition.append(_condition(tok, alias_map, base_dict))
384
344
  elif isinstance(tok, Parenthesis):
385
- current_condition.append(_where(tok, alias_map, baseDict))
386
- current_condition.sort()
387
- if keyword == " AND " or isParanthesis:
388
- return "(" + keyword.join(current_condition) + ")"
389
- else:
390
- return keyword.join(current_condition)
345
+ current_condition.append('(' + _where(tok, alias_map, base_dict) + ')')
346
+ current_condition.sort()
347
+ if keyword == " AND " or is_paranthesis:
348
+ return "(" + keyword.join(current_condition) + ")"
349
+ else:
350
+ return keyword.join(current_condition)
391
351
 
392
352
 
393
353
  def _limit(limit):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql_testing_tools
3
- Version: 0.2.11
3
+ Version: 0.2.12
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Requires-Dist: sqlparse>=0.5.1
@@ -135,6 +135,10 @@ res = checkEquality()
135
135
 
136
136
  ### Changelog
137
137
 
138
+ ##### V 0.2.12
139
+ - fixed bug when having only one colum selected
140
+ - fixed bug with nested conditions
141
+
138
142
  ##### V 0.2.11
139
143
  - fixed irrelevant equality order if both sides aren't literals
140
144