sqlspec 0.13.1__py3-none-any.whl → 0.16.2__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 sqlspec might be problematic. Click here for more details.

Files changed (185) hide show
  1. sqlspec/__init__.py +71 -8
  2. sqlspec/__main__.py +12 -0
  3. sqlspec/__metadata__.py +1 -3
  4. sqlspec/_serialization.py +1 -2
  5. sqlspec/_sql.py +930 -136
  6. sqlspec/_typing.py +278 -142
  7. sqlspec/adapters/adbc/__init__.py +4 -3
  8. sqlspec/adapters/adbc/_types.py +12 -0
  9. sqlspec/adapters/adbc/config.py +116 -285
  10. sqlspec/adapters/adbc/driver.py +462 -340
  11. sqlspec/adapters/aiosqlite/__init__.py +18 -3
  12. sqlspec/adapters/aiosqlite/_types.py +13 -0
  13. sqlspec/adapters/aiosqlite/config.py +202 -150
  14. sqlspec/adapters/aiosqlite/driver.py +226 -247
  15. sqlspec/adapters/asyncmy/__init__.py +18 -3
  16. sqlspec/adapters/asyncmy/_types.py +12 -0
  17. sqlspec/adapters/asyncmy/config.py +80 -199
  18. sqlspec/adapters/asyncmy/driver.py +257 -215
  19. sqlspec/adapters/asyncpg/__init__.py +19 -4
  20. sqlspec/adapters/asyncpg/_types.py +17 -0
  21. sqlspec/adapters/asyncpg/config.py +81 -214
  22. sqlspec/adapters/asyncpg/driver.py +284 -359
  23. sqlspec/adapters/bigquery/__init__.py +17 -3
  24. sqlspec/adapters/bigquery/_types.py +12 -0
  25. sqlspec/adapters/bigquery/config.py +191 -299
  26. sqlspec/adapters/bigquery/driver.py +474 -634
  27. sqlspec/adapters/duckdb/__init__.py +14 -3
  28. sqlspec/adapters/duckdb/_types.py +12 -0
  29. sqlspec/adapters/duckdb/config.py +414 -397
  30. sqlspec/adapters/duckdb/driver.py +342 -393
  31. sqlspec/adapters/oracledb/__init__.py +19 -5
  32. sqlspec/adapters/oracledb/_types.py +14 -0
  33. sqlspec/adapters/oracledb/config.py +123 -458
  34. sqlspec/adapters/oracledb/driver.py +505 -531
  35. sqlspec/adapters/psqlpy/__init__.py +13 -3
  36. sqlspec/adapters/psqlpy/_types.py +11 -0
  37. sqlspec/adapters/psqlpy/config.py +93 -307
  38. sqlspec/adapters/psqlpy/driver.py +504 -213
  39. sqlspec/adapters/psycopg/__init__.py +19 -5
  40. sqlspec/adapters/psycopg/_types.py +17 -0
  41. sqlspec/adapters/psycopg/config.py +143 -472
  42. sqlspec/adapters/psycopg/driver.py +704 -825
  43. sqlspec/adapters/sqlite/__init__.py +14 -3
  44. sqlspec/adapters/sqlite/_types.py +11 -0
  45. sqlspec/adapters/sqlite/config.py +208 -142
  46. sqlspec/adapters/sqlite/driver.py +263 -278
  47. sqlspec/base.py +105 -9
  48. sqlspec/{statement/builder → builder}/__init__.py +12 -14
  49. sqlspec/{statement/builder/base.py → builder/_base.py} +184 -86
  50. sqlspec/{statement/builder/column.py → builder/_column.py} +97 -60
  51. sqlspec/{statement/builder/ddl.py → builder/_ddl.py} +61 -131
  52. sqlspec/{statement/builder → builder}/_ddl_utils.py +4 -10
  53. sqlspec/{statement/builder/delete.py → builder/_delete.py} +10 -30
  54. sqlspec/builder/_insert.py +421 -0
  55. sqlspec/builder/_merge.py +71 -0
  56. sqlspec/{statement/builder → builder}/_parsing_utils.py +49 -26
  57. sqlspec/builder/_select.py +170 -0
  58. sqlspec/{statement/builder/update.py → builder/_update.py} +16 -20
  59. sqlspec/builder/mixins/__init__.py +55 -0
  60. sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
  61. sqlspec/{statement/builder/mixins/_delete_from.py → builder/mixins/_delete_operations.py} +8 -1
  62. sqlspec/builder/mixins/_insert_operations.py +244 -0
  63. sqlspec/{statement/builder/mixins/_join.py → builder/mixins/_join_operations.py} +45 -13
  64. sqlspec/{statement/builder/mixins/_merge_clauses.py → builder/mixins/_merge_operations.py} +188 -30
  65. sqlspec/builder/mixins/_order_limit_operations.py +135 -0
  66. sqlspec/builder/mixins/_pivot_operations.py +153 -0
  67. sqlspec/builder/mixins/_select_operations.py +604 -0
  68. sqlspec/builder/mixins/_update_operations.py +202 -0
  69. sqlspec/builder/mixins/_where_clause.py +644 -0
  70. sqlspec/cli.py +247 -0
  71. sqlspec/config.py +183 -138
  72. sqlspec/core/__init__.py +63 -0
  73. sqlspec/core/cache.py +871 -0
  74. sqlspec/core/compiler.py +417 -0
  75. sqlspec/core/filters.py +830 -0
  76. sqlspec/core/hashing.py +310 -0
  77. sqlspec/core/parameters.py +1237 -0
  78. sqlspec/core/result.py +677 -0
  79. sqlspec/{statement → core}/splitter.py +321 -191
  80. sqlspec/core/statement.py +676 -0
  81. sqlspec/driver/__init__.py +7 -10
  82. sqlspec/driver/_async.py +422 -163
  83. sqlspec/driver/_common.py +545 -287
  84. sqlspec/driver/_sync.py +426 -160
  85. sqlspec/driver/mixins/__init__.py +2 -13
  86. sqlspec/driver/mixins/_result_tools.py +193 -0
  87. sqlspec/driver/mixins/_sql_translator.py +65 -14
  88. sqlspec/exceptions.py +5 -252
  89. sqlspec/extensions/aiosql/adapter.py +93 -96
  90. sqlspec/extensions/litestar/__init__.py +2 -1
  91. sqlspec/extensions/litestar/cli.py +48 -0
  92. sqlspec/extensions/litestar/config.py +0 -1
  93. sqlspec/extensions/litestar/handlers.py +15 -26
  94. sqlspec/extensions/litestar/plugin.py +21 -16
  95. sqlspec/extensions/litestar/providers.py +17 -52
  96. sqlspec/loader.py +423 -104
  97. sqlspec/migrations/__init__.py +35 -0
  98. sqlspec/migrations/base.py +414 -0
  99. sqlspec/migrations/commands.py +443 -0
  100. sqlspec/migrations/loaders.py +402 -0
  101. sqlspec/migrations/runner.py +213 -0
  102. sqlspec/migrations/tracker.py +140 -0
  103. sqlspec/migrations/utils.py +129 -0
  104. sqlspec/protocols.py +51 -186
  105. sqlspec/storage/__init__.py +1 -1
  106. sqlspec/storage/backends/base.py +37 -40
  107. sqlspec/storage/backends/fsspec.py +136 -112
  108. sqlspec/storage/backends/obstore.py +138 -160
  109. sqlspec/storage/capabilities.py +5 -4
  110. sqlspec/storage/registry.py +57 -106
  111. sqlspec/typing.py +136 -115
  112. sqlspec/utils/__init__.py +2 -2
  113. sqlspec/utils/correlation.py +0 -3
  114. sqlspec/utils/deprecation.py +6 -6
  115. sqlspec/utils/fixtures.py +6 -6
  116. sqlspec/utils/logging.py +0 -2
  117. sqlspec/utils/module_loader.py +7 -12
  118. sqlspec/utils/singleton.py +0 -1
  119. sqlspec/utils/sync_tools.py +17 -38
  120. sqlspec/utils/text.py +12 -51
  121. sqlspec/utils/type_guards.py +482 -235
  122. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/METADATA +7 -2
  123. sqlspec-0.16.2.dist-info/RECORD +134 -0
  124. sqlspec-0.16.2.dist-info/entry_points.txt +2 -0
  125. sqlspec/driver/connection.py +0 -207
  126. sqlspec/driver/mixins/_csv_writer.py +0 -91
  127. sqlspec/driver/mixins/_pipeline.py +0 -512
  128. sqlspec/driver/mixins/_result_utils.py +0 -140
  129. sqlspec/driver/mixins/_storage.py +0 -926
  130. sqlspec/driver/mixins/_type_coercion.py +0 -130
  131. sqlspec/driver/parameters.py +0 -138
  132. sqlspec/service/__init__.py +0 -4
  133. sqlspec/service/_util.py +0 -147
  134. sqlspec/service/base.py +0 -1131
  135. sqlspec/service/pagination.py +0 -26
  136. sqlspec/statement/__init__.py +0 -21
  137. sqlspec/statement/builder/insert.py +0 -288
  138. sqlspec/statement/builder/merge.py +0 -95
  139. sqlspec/statement/builder/mixins/__init__.py +0 -65
  140. sqlspec/statement/builder/mixins/_aggregate_functions.py +0 -250
  141. sqlspec/statement/builder/mixins/_case_builder.py +0 -91
  142. sqlspec/statement/builder/mixins/_common_table_expr.py +0 -90
  143. sqlspec/statement/builder/mixins/_from.py +0 -63
  144. sqlspec/statement/builder/mixins/_group_by.py +0 -118
  145. sqlspec/statement/builder/mixins/_having.py +0 -35
  146. sqlspec/statement/builder/mixins/_insert_from_select.py +0 -47
  147. sqlspec/statement/builder/mixins/_insert_into.py +0 -36
  148. sqlspec/statement/builder/mixins/_insert_values.py +0 -67
  149. sqlspec/statement/builder/mixins/_limit_offset.py +0 -53
  150. sqlspec/statement/builder/mixins/_order_by.py +0 -46
  151. sqlspec/statement/builder/mixins/_pivot.py +0 -79
  152. sqlspec/statement/builder/mixins/_returning.py +0 -37
  153. sqlspec/statement/builder/mixins/_select_columns.py +0 -61
  154. sqlspec/statement/builder/mixins/_set_ops.py +0 -122
  155. sqlspec/statement/builder/mixins/_unpivot.py +0 -77
  156. sqlspec/statement/builder/mixins/_update_from.py +0 -55
  157. sqlspec/statement/builder/mixins/_update_set.py +0 -94
  158. sqlspec/statement/builder/mixins/_update_table.py +0 -29
  159. sqlspec/statement/builder/mixins/_where.py +0 -401
  160. sqlspec/statement/builder/mixins/_window_functions.py +0 -86
  161. sqlspec/statement/builder/select.py +0 -221
  162. sqlspec/statement/filters.py +0 -596
  163. sqlspec/statement/parameter_manager.py +0 -220
  164. sqlspec/statement/parameters.py +0 -867
  165. sqlspec/statement/pipelines/__init__.py +0 -210
  166. sqlspec/statement/pipelines/analyzers/__init__.py +0 -9
  167. sqlspec/statement/pipelines/analyzers/_analyzer.py +0 -646
  168. sqlspec/statement/pipelines/context.py +0 -115
  169. sqlspec/statement/pipelines/transformers/__init__.py +0 -7
  170. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +0 -88
  171. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +0 -1247
  172. sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +0 -76
  173. sqlspec/statement/pipelines/validators/__init__.py +0 -23
  174. sqlspec/statement/pipelines/validators/_dml_safety.py +0 -290
  175. sqlspec/statement/pipelines/validators/_parameter_style.py +0 -370
  176. sqlspec/statement/pipelines/validators/_performance.py +0 -718
  177. sqlspec/statement/pipelines/validators/_security.py +0 -967
  178. sqlspec/statement/result.py +0 -435
  179. sqlspec/statement/sql.py +0 -1704
  180. sqlspec/statement/sql_compiler.py +0 -140
  181. sqlspec/utils/cached_property.py +0 -25
  182. sqlspec-0.13.1.dist-info/RECORD +0 -150
  183. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/WHEEL +0 -0
  184. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/LICENSE +0 -0
  185. {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/NOTICE +0 -0
@@ -17,103 +17,104 @@ __all__ = ("Column", "ColumnExpression", "FunctionColumn")
17
17
  class ColumnExpression:
18
18
  """Base class for column expressions that can be combined with operators."""
19
19
 
20
+ __slots__ = ("_expression",)
21
+
20
22
  def __init__(self, expression: exp.Expression) -> None:
21
- self._expr = expression
23
+ self._expression = expression
22
24
 
23
25
  def __and__(self, other: "ColumnExpression") -> "ColumnExpression":
24
26
  """Combine with AND operator (&)."""
25
27
  if not isinstance(other, ColumnExpression):
26
28
  return NotImplemented
27
- return ColumnExpression(exp.And(this=self._expr, expression=other._expr))
29
+ return ColumnExpression(exp.And(this=self._expression, expression=other._expression))
28
30
 
29
31
  def __or__(self, other: "ColumnExpression") -> "ColumnExpression":
30
32
  """Combine with OR operator (|)."""
31
33
  if not isinstance(other, ColumnExpression):
32
34
  return NotImplemented
33
- return ColumnExpression(exp.Or(this=self._expr, expression=other._expr))
35
+ return ColumnExpression(exp.Or(this=self._expression, expression=other._expression))
34
36
 
35
37
  def __invert__(self) -> "ColumnExpression":
36
38
  """Apply NOT operator (~)."""
37
- return ColumnExpression(exp.Not(this=self._expr))
39
+ return ColumnExpression(exp.Not(this=self._expression))
38
40
 
39
41
  def __bool__(self) -> bool:
40
42
  """Prevent accidental use of 'and'/'or' keywords."""
41
43
  msg = (
42
44
  "Cannot use 'and'/'or' operators on ColumnExpression. "
43
45
  "Use '&'/'|' operators instead. "
44
- f"Expression: {self._expr.sql()}"
46
+ f"Expression: {self._expression.sql()}"
45
47
  )
46
48
  raise TypeError(msg)
47
49
 
48
50
  @property
49
51
  def sqlglot_expression(self) -> exp.Expression:
50
52
  """Get the underlying SQLGlot expression."""
51
- return self._expr
53
+ return self._expression
52
54
 
53
55
 
54
56
  class Column:
55
57
  """Represents a database column with Python operator support."""
56
58
 
59
+ __slots__ = ("_expression", "name", "table")
60
+
57
61
  def __init__(self, name: str, table: Optional[str] = None) -> None:
58
62
  self.name = name
59
63
  self.table = table
60
64
 
61
- # Create SQLGlot column expression
62
65
  if table:
63
- self._expr = exp.Column(this=exp.Identifier(this=name), table=exp.Identifier(this=table))
66
+ self._expression = exp.Column(this=exp.Identifier(this=name), table=exp.Identifier(this=table))
64
67
  else:
65
- self._expr = exp.Column(this=exp.Identifier(this=name))
68
+ self._expression = exp.Column(this=exp.Identifier(this=name))
66
69
 
67
- # Comparison operators
68
70
  def __eq__(self, other: object) -> ColumnExpression: # type: ignore[override]
69
71
  """Equal to (==)."""
70
72
  if other is None:
71
- return ColumnExpression(exp.Is(this=self._expr, expression=exp.Null()))
72
- return ColumnExpression(exp.EQ(this=self._expr, expression=exp.convert(other)))
73
+ return ColumnExpression(exp.Is(this=self._expression, expression=exp.Null()))
74
+ return ColumnExpression(exp.EQ(this=self._expression, expression=exp.convert(other)))
73
75
 
74
76
  def __ne__(self, other: object) -> ColumnExpression: # type: ignore[override]
75
77
  """Not equal to (!=)."""
76
78
  if other is None:
77
- return ColumnExpression(exp.Not(this=exp.Is(this=self._expr, expression=exp.Null())))
78
- return ColumnExpression(exp.NEQ(this=self._expr, expression=exp.convert(other)))
79
+ return ColumnExpression(exp.Not(this=exp.Is(this=self._expression, expression=exp.Null())))
80
+ return ColumnExpression(exp.NEQ(this=self._expression, expression=exp.convert(other)))
79
81
 
80
82
  def __gt__(self, other: Any) -> ColumnExpression:
81
83
  """Greater than (>)."""
82
- return ColumnExpression(exp.GT(this=self._expr, expression=exp.convert(other)))
84
+ return ColumnExpression(exp.GT(this=self._expression, expression=exp.convert(other)))
83
85
 
84
86
  def __ge__(self, other: Any) -> ColumnExpression:
85
87
  """Greater than or equal (>=)."""
86
- return ColumnExpression(exp.GTE(this=self._expr, expression=exp.convert(other)))
88
+ return ColumnExpression(exp.GTE(this=self._expression, expression=exp.convert(other)))
87
89
 
88
90
  def __lt__(self, other: Any) -> ColumnExpression:
89
91
  """Less than (<)."""
90
- return ColumnExpression(exp.LT(this=self._expr, expression=exp.convert(other)))
92
+ return ColumnExpression(exp.LT(this=self._expression, expression=exp.convert(other)))
91
93
 
92
94
  def __le__(self, other: Any) -> ColumnExpression:
93
95
  """Less than or equal (<=)."""
94
- return ColumnExpression(exp.LTE(this=self._expr, expression=exp.convert(other)))
96
+ return ColumnExpression(exp.LTE(this=self._expression, expression=exp.convert(other)))
95
97
 
96
98
  def __invert__(self) -> ColumnExpression:
97
99
  """Apply NOT operator (~)."""
98
- return ColumnExpression(exp.Not(this=self._expr))
100
+ return ColumnExpression(exp.Not(this=self._expression))
99
101
 
100
- # SQL-specific methods
101
102
  def like(self, pattern: str, escape: Optional[str] = None) -> ColumnExpression:
102
103
  """SQL LIKE pattern matching."""
103
104
  if escape:
104
- like_expr = exp.Like(this=self._expr, expression=exp.convert(pattern), escape=exp.convert(escape))
105
+ like_expr = exp.Like(this=self._expression, expression=exp.convert(pattern), escape=exp.convert(escape))
105
106
  else:
106
- like_expr = exp.Like(this=self._expr, expression=exp.convert(pattern))
107
+ like_expr = exp.Like(this=self._expression, expression=exp.convert(pattern))
107
108
  return ColumnExpression(like_expr)
108
109
 
109
110
  def ilike(self, pattern: str) -> ColumnExpression:
110
111
  """Case-insensitive LIKE."""
111
- return ColumnExpression(exp.ILike(this=self._expr, expression=exp.convert(pattern)))
112
+ return ColumnExpression(exp.ILike(this=self._expression, expression=exp.convert(pattern)))
112
113
 
113
114
  def in_(self, values: Iterable[Any]) -> ColumnExpression:
114
115
  """SQL IN clause."""
115
116
  converted_values = [exp.convert(v) for v in values]
116
- return ColumnExpression(exp.In(this=self._expr, expressions=converted_values))
117
+ return ColumnExpression(exp.In(this=self._expression, expressions=converted_values))
117
118
 
118
119
  def not_in(self, values: Iterable[Any]) -> ColumnExpression:
119
120
  """SQL NOT IN clause."""
@@ -121,15 +122,15 @@ class Column:
121
122
 
122
123
  def between(self, start: Any, end: Any) -> ColumnExpression:
123
124
  """SQL BETWEEN clause."""
124
- return ColumnExpression(exp.Between(this=self._expr, low=exp.convert(start), high=exp.convert(end)))
125
+ return ColumnExpression(exp.Between(this=self._expression, low=exp.convert(start), high=exp.convert(end)))
125
126
 
126
127
  def is_null(self) -> ColumnExpression:
127
128
  """SQL IS NULL."""
128
- return ColumnExpression(exp.Is(this=self._expr, expression=exp.Null()))
129
+ return ColumnExpression(exp.Is(this=self._expression, expression=exp.Null()))
129
130
 
130
131
  def is_not_null(self) -> ColumnExpression:
131
132
  """SQL IS NOT NULL."""
132
- return ColumnExpression(exp.Not(this=exp.Is(this=self._expr, expression=exp.Null())))
133
+ return ColumnExpression(exp.Not(this=exp.Is(this=self._expression, expression=exp.Null())))
133
134
 
134
135
  def not_like(self, pattern: str, escape: Optional[str] = None) -> ColumnExpression:
135
136
  """SQL NOT LIKE pattern matching."""
@@ -142,67 +143,103 @@ class Column:
142
143
  def any_(self, values: Iterable[Any]) -> ColumnExpression:
143
144
  """SQL = ANY(...) clause."""
144
145
  converted_values = [exp.convert(v) for v in values]
145
- return ColumnExpression(exp.EQ(this=self._expr, expression=exp.Any(expressions=converted_values)))
146
+ return ColumnExpression(exp.EQ(this=self._expression, expression=exp.Any(expressions=converted_values)))
146
147
 
147
148
  def not_any_(self, values: Iterable[Any]) -> ColumnExpression:
148
149
  """SQL <> ANY(...) clause."""
149
150
  converted_values = [exp.convert(v) for v in values]
150
- return ColumnExpression(exp.NEQ(this=self._expr, expression=exp.Any(expressions=converted_values)))
151
+ return ColumnExpression(exp.NEQ(this=self._expression, expression=exp.Any(expressions=converted_values)))
151
152
 
152
- # SQL Functions
153
153
  def lower(self) -> "FunctionColumn":
154
154
  """SQL LOWER() function."""
155
- return FunctionColumn(exp.Lower(this=self._expr))
155
+ return FunctionColumn(exp.Lower(this=self._expression))
156
156
 
157
157
  def upper(self) -> "FunctionColumn":
158
158
  """SQL UPPER() function."""
159
- return FunctionColumn(exp.Upper(this=self._expr))
159
+ return FunctionColumn(exp.Upper(this=self._expression))
160
160
 
161
161
  def length(self) -> "FunctionColumn":
162
162
  """SQL LENGTH() function."""
163
- return FunctionColumn(exp.Length(this=self._expr))
163
+ return FunctionColumn(exp.Length(this=self._expression))
164
164
 
165
165
  def trim(self) -> "FunctionColumn":
166
166
  """SQL TRIM() function."""
167
- return FunctionColumn(exp.Trim(this=self._expr))
167
+ return FunctionColumn(exp.Trim(this=self._expression))
168
168
 
169
169
  def abs(self) -> "FunctionColumn":
170
170
  """SQL ABS() function."""
171
- return FunctionColumn(exp.Abs(this=self._expr))
171
+ return FunctionColumn(exp.Abs(this=self._expression))
172
172
 
173
173
  def round(self, decimals: int = 0) -> "FunctionColumn":
174
174
  """SQL ROUND() function."""
175
175
  if decimals == 0:
176
- return FunctionColumn(exp.Round(this=self._expr))
177
- return FunctionColumn(exp.Round(this=self._expr, expression=exp.Literal.number(decimals)))
176
+ return FunctionColumn(exp.Round(this=self._expression))
177
+ return FunctionColumn(exp.Round(this=self._expression, expression=exp.convert(decimals)))
178
178
 
179
179
  def floor(self) -> "FunctionColumn":
180
180
  """SQL FLOOR() function."""
181
- return FunctionColumn(exp.Floor(this=self._expr))
181
+ return FunctionColumn(exp.Floor(this=self._expression))
182
182
 
183
183
  def ceil(self) -> "FunctionColumn":
184
184
  """SQL CEIL() function."""
185
- return FunctionColumn(exp.Ceil(this=self._expr))
185
+ return FunctionColumn(exp.Ceil(this=self._expression))
186
186
 
187
187
  def substring(self, start: int, length: Optional[int] = None) -> "FunctionColumn":
188
188
  """SQL SUBSTRING() function."""
189
- args = [exp.Literal.number(start)]
189
+ args = [exp.convert(start)]
190
190
  if length is not None:
191
- args.append(exp.Literal.number(length))
192
- return FunctionColumn(exp.Substring(this=self._expr, expressions=args))
191
+ args.append(exp.convert(length))
192
+ return FunctionColumn(exp.Substring(this=self._expression, expressions=args))
193
193
 
194
194
  def coalesce(self, *values: Any) -> "FunctionColumn":
195
195
  """SQL COALESCE() function."""
196
- expressions = [self._expr] + [exp.convert(v) for v in values]
196
+ expressions = [self._expression] + [exp.convert(v) for v in values]
197
197
  return FunctionColumn(exp.Coalesce(expressions=expressions))
198
198
 
199
199
  def cast(self, data_type: str) -> "FunctionColumn":
200
200
  """SQL CAST() function."""
201
- return FunctionColumn(exp.Cast(this=self._expr, to=exp.DataType.build(data_type)))
201
+ return FunctionColumn(exp.Cast(this=self._expression, to=exp.DataType.build(data_type)))
202
+
203
+ def count(self) -> "FunctionColumn":
204
+ """SQL COUNT() function."""
205
+ return FunctionColumn(exp.Count(this=self._expression))
206
+
207
+ def sum(self) -> "FunctionColumn":
208
+ """SQL SUM() function."""
209
+ return FunctionColumn(exp.Sum(this=self._expression))
210
+
211
+ def avg(self) -> "FunctionColumn":
212
+ """SQL AVG() function."""
213
+ return FunctionColumn(exp.Avg(this=self._expression))
214
+
215
+ def min(self) -> "FunctionColumn":
216
+ """SQL MIN() function."""
217
+ return FunctionColumn(exp.Min(this=self._expression))
218
+
219
+ def max(self) -> "FunctionColumn":
220
+ """SQL MAX() function."""
221
+ return FunctionColumn(exp.Max(this=self._expression))
222
+
223
+ def count_distinct(self) -> "FunctionColumn":
224
+ """SQL COUNT(DISTINCT column) function."""
225
+ return FunctionColumn(exp.Count(this=exp.Distinct(expressions=[self._expression])))
226
+
227
+ @staticmethod
228
+ def count_all() -> "FunctionColumn":
229
+ """SQL COUNT(*) function."""
230
+ return FunctionColumn(exp.Count(this=exp.Star()))
202
231
 
203
232
  def alias(self, alias_name: str) -> exp.Expression:
204
233
  """Create an aliased column expression."""
205
- return exp.Alias(this=self._expr, alias=alias_name)
234
+ return exp.Alias(this=self._expression, alias=alias_name)
235
+
236
+ def asc(self) -> exp.Ordered:
237
+ """Create an ASC ordering expression."""
238
+ return exp.Ordered(this=self._expression, desc=False)
239
+
240
+ def desc(self) -> exp.Ordered:
241
+ """Create a DESC ordering expression."""
242
+ return exp.Ordered(this=self._expression, desc=True)
206
243
 
207
244
  def __repr__(self) -> str:
208
245
  if self.table:
@@ -217,26 +254,28 @@ class Column:
217
254
  class FunctionColumn:
218
255
  """Represents the result of a SQL function call on a column."""
219
256
 
257
+ __slots__ = ("_expression",)
258
+
220
259
  def __init__(self, expression: exp.Expression) -> None:
221
- self._expr = expression
260
+ self._expression = expression
222
261
 
223
262
  def __eq__(self, other: object) -> ColumnExpression: # type: ignore[override]
224
- return ColumnExpression(exp.EQ(this=self._expr, expression=exp.convert(other)))
263
+ return ColumnExpression(exp.EQ(this=self._expression, expression=exp.convert(other)))
225
264
 
226
265
  def __ne__(self, other: object) -> ColumnExpression: # type: ignore[override]
227
- return ColumnExpression(exp.NEQ(this=self._expr, expression=exp.convert(other)))
266
+ return ColumnExpression(exp.NEQ(this=self._expression, expression=exp.convert(other)))
228
267
 
229
268
  def like(self, pattern: str) -> ColumnExpression:
230
- return ColumnExpression(exp.Like(this=self._expr, expression=exp.convert(pattern)))
269
+ return ColumnExpression(exp.Like(this=self._expression, expression=exp.convert(pattern)))
231
270
 
232
271
  def ilike(self, pattern: str) -> ColumnExpression:
233
272
  """Case-insensitive LIKE."""
234
- return ColumnExpression(exp.ILike(this=self._expr, expression=exp.convert(pattern)))
273
+ return ColumnExpression(exp.ILike(this=self._expression, expression=exp.convert(pattern)))
235
274
 
236
275
  def in_(self, values: Iterable[Any]) -> ColumnExpression:
237
276
  """SQL IN clause."""
238
277
  converted_values = [exp.convert(v) for v in values]
239
- return ColumnExpression(exp.In(this=self._expr, expressions=converted_values))
278
+ return ColumnExpression(exp.In(this=self._expression, expressions=converted_values))
240
279
 
241
280
  def not_in_(self, values: Iterable[Any]) -> ColumnExpression:
242
281
  """SQL NOT IN clause."""
@@ -252,32 +291,30 @@ class FunctionColumn:
252
291
 
253
292
  def between(self, start: Any, end: Any) -> ColumnExpression:
254
293
  """SQL BETWEEN clause."""
255
- return ColumnExpression(exp.Between(this=self._expr, low=exp.convert(start), high=exp.convert(end)))
294
+ return ColumnExpression(exp.Between(this=self._expression, low=exp.convert(start), high=exp.convert(end)))
256
295
 
257
296
  def is_null(self) -> ColumnExpression:
258
297
  """SQL IS NULL."""
259
- return ColumnExpression(exp.Is(this=self._expr, expression=exp.Null()))
298
+ return ColumnExpression(exp.Is(this=self._expression, expression=exp.Null()))
260
299
 
261
300
  def is_not_null(self) -> ColumnExpression:
262
301
  """SQL IS NOT NULL."""
263
- return ColumnExpression(exp.Not(this=exp.Is(this=self._expr, expression=exp.Null())))
302
+ return ColumnExpression(exp.Not(this=exp.Is(this=self._expression, expression=exp.Null())))
264
303
 
265
304
  def any_(self, values: Iterable[Any]) -> ColumnExpression:
266
305
  """SQL = ANY(...) clause."""
267
306
  converted_values = [exp.convert(v) for v in values]
268
- return ColumnExpression(exp.EQ(this=self._expr, expression=exp.Any(expressions=converted_values)))
307
+ return ColumnExpression(exp.EQ(this=self._expression, expression=exp.Any(expressions=converted_values)))
269
308
 
270
309
  def not_any_(self, values: Iterable[Any]) -> ColumnExpression:
271
310
  """SQL <> ANY(...) clause."""
272
311
  converted_values = [exp.convert(v) for v in values]
273
- return ColumnExpression(exp.NEQ(this=self._expr, expression=exp.Any(expressions=converted_values)))
312
+ return ColumnExpression(exp.NEQ(this=self._expression, expression=exp.Any(expressions=converted_values)))
274
313
 
275
314
  def alias(self, alias_name: str) -> exp.Expression:
276
315
  """Create an aliased function expression."""
277
- return exp.Alias(this=self._expr, alias=alias_name)
278
-
279
- # Add other operators as needed...
316
+ return exp.Alias(this=self._expression, alias=alias_name)
280
317
 
281
318
  def __hash__(self) -> int:
282
319
  """Hash based on the SQL expression."""
283
- return hash(self._expr.sql() if has_sql_method(self._expr) else str(self._expr))
320
+ return hash(self._expression.sql() if has_sql_method(self._expression) else str(self._expression))