velocity-python 0.0.67__py3-none-any.whl → 0.0.69__py3-none-any.whl

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.

Potentially problematic release.


This version of velocity-python might be problematic. Click here for more details.

velocity/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = version = "0.0.67"
1
+ __version__ = version = "0.0.69"
2
2
 
3
3
  from . import aws
4
4
  from . import db
@@ -110,16 +110,13 @@ class SQL:
110
110
  "distinct" in c.lower() for c in columns
111
111
  ): # Check if "distinct" exists in any entry
112
112
  distinct = True
113
- columns = [
114
- c.replace("distinct", "", 1).strip() if "distinct" in c.lower() else c
115
- for c in columns
116
- ]
113
+ columns = [re.sub(r"(?i)\bdistinct\b", "", c).strip() for c in columns]
117
114
 
118
115
  processed_columns = []
119
116
  for col in columns:
120
117
  processed_columns.append(
121
118
  th.resolve_references(
122
- col, options={"alias_column": True, "alias_table": True}
119
+ col, options={"alias_column": True, "alias_table": True, bypass_on_error=True}
123
120
  )
124
121
  )
125
122
 
@@ -90,14 +90,18 @@ class TableHelper:
90
90
  Resolves pointer syntax or table alias references.
91
91
  `options` can control whether to alias columns and/or tables.
92
92
  """
93
+ if not key:
94
+ raise Exception(f"Invalid key={key}")
93
95
  if options is None:
94
96
  options = {"alias_column": True, "alias_table": False, "alias_only": False}
95
-
96
97
  column = self.extract_column_name(key)
97
- alias = self.get_table_alias("current_table")
98
- if not key or not column:
99
- raise Exception(f"Invalid key or column: key={key}, column={column}")
100
98
 
99
+ if not column:
100
+ if options.get("bypass_on_error"):
101
+ return key
102
+ raise Exception(f"Invalid column={column}")
103
+
104
+ alias = self.get_table_alias("current_table")
101
105
  if not self.has_pointer(column):
102
106
  # Standard column
103
107
  if options.get("alias_table") and alias != "A":
@@ -143,47 +147,56 @@ class TableHelper:
143
147
  """
144
148
  Extracts the 'bare' column name from a SQL expression.
145
149
 
146
- This version intelligently detects window functions like ROW_NUMBER() OVER(ORDER BY x)
147
- and returns the actual column used inside ORDER BY.
150
+ Supports:
151
+ - Aliases (AS ...)
152
+ - Window functions (OVER(... ORDER BY ...))
153
+ - CAST(... AS ...)
154
+ - CASE WHEN ... THEN ... ELSE ... END
155
+ - Nested function calls
156
+ - Grabs column from inside expressions (e.g. PLAID_ERROR from SUM(CASE...))
148
157
 
149
158
  Args:
150
- sql_expression (str): Complex SQL expression (may include OVER, CAST, CASE, etc.)
159
+ sql_expression (str): SQL expression (SELECT column) string.
151
160
 
152
161
  Returns:
153
- str or None: Inferred base column name, like "amount", "a.email", or "*"
162
+ str or None: Extracted column name or None if undetectable.
154
163
  """
155
- import re
156
-
157
164
  expr = sql_expression.replace('"', "").strip()
158
165
 
159
- # Step 1: Remove alias
166
+ # Remove trailing alias
160
167
  expr = re.sub(r"(?i)\s+as\s+\w+$", "", expr).strip()
161
168
 
162
- # Step 2: Pull column from ORDER BY inside OVER()
163
- over_match = re.search(r"(?i)OVER\s*\(\s*ORDER\s+BY\s+([^)\s]+)", expr)
169
+ # If OVER clause: extract column inside ORDER BY
170
+ over_match = re.search(r"(?i)OVER\s*\(\s*ORDER\s+BY\s+([^\s,)]+)", expr)
164
171
  if over_match:
165
- column = over_match.group(1).strip(",")
166
- return column
167
-
168
- # Step 3: Strip CAST(x AS type)
169
- expr = re.sub(r"(?i)CAST\s*\((.*?)\s+AS\s+[^\)]+\)", r"\1", expr)
170
-
171
- # Step 4: Strip CASE WHEN ... THEN ... ELSE ... END
172
- expr = re.sub(
173
- r"(?i)CASE\s+WHEN\s+(.*?)\s+THEN\s+.*?\s+(ELSE\s+.*?)?END", r"\1", expr
174
- )
172
+ return over_match.group(1)
173
+
174
+ # Remove CAST(... AS ...)
175
+ while re.search(r"(?i)CAST\s*\(([^()]+?)\s+AS\s+[^\)]+\)", expr):
176
+ expr = re.sub(r"(?i)CAST\s*\(([^()]+?)\s+AS\s+[^\)]+\)", r"\1", expr)
177
+
178
+ # Remove CASE WHEN ... THEN ... ELSE ... END, keep just the WHEN part
179
+ while re.search(
180
+ r"(?i)CASE\s+WHEN\s+(.+?)\s+THEN\s+.+?(?:\s+ELSE\s+.+?)?\s+END", expr
181
+ ):
182
+ expr = re.sub(
183
+ r"(?i)CASE\s+WHEN\s+(.+?)\s+THEN\s+.+?(?:\s+ELSE\s+.+?)?\s+END",
184
+ r"\1",
185
+ expr,
186
+ )
175
187
 
176
- # Step 5: Remove nested function calls
177
- while re.search(r"\b\w+\s*\([^()]*\)", expr):
178
- expr = re.sub(r"\b\w+\s*\(([^()]*)\)", r"\1", expr)
188
+ # Unwrap function calls (SUM(...), MAX(...), etc.)
189
+ while re.search(r"\b\w+\s*\(([^()]+)\)", expr):
190
+ expr = re.sub(r"\b\w+\s*\(([^()]+)\)", r"\1", expr)
179
191
 
180
- # Step 6: Keep only first expression if comma-separated
192
+ # If multiple columns, take the first
181
193
  if "," in expr:
182
194
  expr = expr.split(",")[0].strip()
183
195
 
184
- # Step 7: Match column-like patterns
185
- pattern = r"^([a-zA-Z_][\w]*\.\*|\*|[a-zA-Z_][\w]*(?:\.[a-zA-Z_][\w]*)?)$"
186
- match = re.search(pattern, expr)
196
+ # Extract column name (basic or dotted like table.col or *)
197
+ match = re.search(
198
+ r"\b([a-zA-Z_][\w]*\.\*|\*|[a-zA-Z_][\w]*(?:\.[a-zA-Z_][\w]*)?)\b", expr
199
+ )
187
200
  return match.group(1) if match else None
188
201
 
189
202
  def are_parentheses_balanced(self, expression):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: velocity-python
3
- Version: 0.0.67
3
+ Version: 0.0.69
4
4
  Summary: A rapid application development library for interfacing with data storage
5
5
  Author-email: Paul Perez <pperez@codeclubs.org>
6
6
  Project-URL: Homepage, https://codeclubs.org/projects/velocity
@@ -1,4 +1,4 @@
1
- velocity/__init__.py,sha256=sWlnhF2G6SCos7NBlC2zOtN-FNPGuLbB3yeepfiHMtY,88
1
+ velocity/__init__.py,sha256=QBkdg_Y9sxtwoFe1Uoi69oz-y-W1UOps4xGyhXTemlA,88
2
2
  velocity/aws/__init__.py,sha256=GBTEr02whnCH3TG-BWCpUC3KfHY3uNxD21g0OvsVJnc,598
3
3
  velocity/aws/handlers/__init__.py,sha256=xnpFZJVlC2uoeeFW4zuPST8wA8ajaQDky5Y6iXZzi3A,172
4
4
  velocity/aws/handlers/context.py,sha256=UIjNR83y2NSIyK8HMPX8t5tpJHFNabiZvNgmmdQL3HA,1822
@@ -24,11 +24,11 @@ velocity/db/servers/sqlite.py,sha256=X210a5pENT9PiVK7f16fxXzFwEsq8fSe58Vouv2xqlk
24
24
  velocity/db/servers/sqlite_reserved.py,sha256=-xmjl-Hgu6lKqkCAXq_6U8_aJX6gvaMgLMLdCt-Ej7o,3006
25
25
  velocity/db/servers/sqlserver.py,sha256=0uGLEWRXiUhrOVTpEA1zvaKq1mcfiaCDp9r7gX-N71g,29914
26
26
  velocity/db/servers/sqlserver_reserved.py,sha256=3LGQYU0qfvk6AbKety96gbzzfLbZ0dNHDPLxKGvvi4Q,4596
27
- velocity/db/servers/tablehelper.py,sha256=-sb9RAj8OUZTuoNQehc1ALxowk11gb3IUCxdaT6Aua4,10735
27
+ velocity/db/servers/tablehelper.py,sha256=t_4Z0j3NT26dCe88ydAskipMoaQyrhgyrs_3hmQ6tDU,11161
28
28
  velocity/db/servers/postgres/__init__.py,sha256=SRqTRrhHkueEzGScG82KVveXC9mfNm6t4XylSCObkXQ,546
29
29
  velocity/db/servers/postgres/operators.py,sha256=A2T1qFwhzPl0fdXVhLZJhh5Qfx-qF8oZsDnxnq2n_V8,389
30
30
  velocity/db/servers/postgres/reserved.py,sha256=5tKLaqFV-HrWRj-nsrxl5KGbmeM3ukn_bPZK36XEu8M,3648
31
- velocity/db/servers/postgres/sql.py,sha256=mGPUrg0M5NGNkCHbMKdL0F01CEfCr883lJlB-qAG6bM,38147
31
+ velocity/db/servers/postgres/sql.py,sha256=XdWT0xAwS3_MOroVAmmpasJQ16NaPCTidMZJOZs_odI,38095
32
32
  velocity/db/servers/postgres/types.py,sha256=Wa45ppVf_pdWul-jYWFRGMl6IdSq8dAp10SKnhL7osQ,3757
33
33
  velocity/misc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  velocity/misc/db.py,sha256=MPgt-kkukKR_Wh_S_5W-MyDgaeoZ4YLoDJ54wU2ppm4,2830
@@ -41,8 +41,8 @@ velocity/misc/tools.py,sha256=_bGneHHA_BV-kUonzw5H3hdJ5AOJRCKfzhgpkFbGqIo,1502
41
41
  velocity/misc/conv/__init__.py,sha256=MLYF58QHjzfDSxb1rdnmLnuEQCa3gnhzzZ30CwZVvQo,40
42
42
  velocity/misc/conv/iconv.py,sha256=d4_BucW8HTIkGNurJ7GWrtuptqUf-9t79ObzjJ5N76U,10603
43
43
  velocity/misc/conv/oconv.py,sha256=h5Lo05DqOQnxoD3y6Px_MQP_V-pBbWf8Hkgkb9Xp1jk,6032
44
- velocity_python-0.0.67.dist-info/licenses/LICENSE,sha256=aoN245GG8s9oRUU89KNiGTU4_4OtnNmVi4hQeChg6rM,1076
45
- velocity_python-0.0.67.dist-info/METADATA,sha256=7BQY5psmqQwrVwTGLl3pI2D_mPmcsqZFT9yd-zvpV5k,8541
46
- velocity_python-0.0.67.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
47
- velocity_python-0.0.67.dist-info/top_level.txt,sha256=JW2vJPmodgdgSz7H6yoZvnxF8S3fTMIv-YJWCT1sNW0,9
48
- velocity_python-0.0.67.dist-info/RECORD,,
44
+ velocity_python-0.0.69.dist-info/licenses/LICENSE,sha256=aoN245GG8s9oRUU89KNiGTU4_4OtnNmVi4hQeChg6rM,1076
45
+ velocity_python-0.0.69.dist-info/METADATA,sha256=-4YMKA00hQC2LXoDX2--HsUA-CWaksoBYl6RFZvoMtk,8541
46
+ velocity_python-0.0.69.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
47
+ velocity_python-0.0.69.dist-info/top_level.txt,sha256=JW2vJPmodgdgSz7H6yoZvnxF8S3fTMIv-YJWCT1sNW0,9
48
+ velocity_python-0.0.69.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.0)
2
+ Generator: setuptools (79.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5