buildaquery 0.1.0__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.
File without changes
@@ -0,0 +1,54 @@
1
+ # Abstract Syntax Tree (AST)
2
+
3
+ The `abstract_syntax_tree` module defines the data structures used to represent SQL queries as an Abstract Syntax Tree. This representation is agnostic of any specific SQL dialect and serves as the intermediate format that the query builder constructs and the compiler translates into SQL.
4
+
5
+ ## Core Concepts
6
+
7
+ The AST is built using a hierarchy of nodes, all inheriting from the base `ASTNode` class.
8
+
9
+ ### Node Categories
10
+
11
+ - **`ExpressionNode`**: Represents values, column references, and operations (e.g., `LiteralNode`, `ColumnNode`, `BinaryOperationNode`, `FunctionCallNode`).
12
+ - **`StatementNode`**: Represents complete SQL statements. Currently, `SelectStatementNode` is the primary implementation.
13
+ - **`FromClauseNode`**: Represents entities that can appear in a `FROM` clause, such as `TableNode` or `JoinClauseNode`.
14
+
15
+ ## Key Components
16
+
17
+ - **`SelectStatementNode`**: The central node for `SELECT` queries. It encapsulates the select list, `FROM` table/joins, `WHERE` conditions, `GROUP BY`, `HAVING`, `ORDER BY`, and pagination (`LIMIT`, `OFFSET`, `TOP`).
18
+ - **`TopClauseNode`**: A specialized node for limiting results, particularly for dialects that support the `TOP` syntax. It is mutually exclusive with standard `LIMIT`/`OFFSET`.
19
+ - **`JoinClauseNode`**: Represents various types of table joins (INNER, LEFT, etc.) with associated join conditions.
20
+ - **Operations**: Support for both binary (e.g., `+`, `-`, `AND`, `OR`) and unary (e.g., `NOT`, `-`) operations.
21
+
22
+ ## Usage
23
+
24
+ Nodes are typically instantiated and composed to build a tree representing a query. For example:
25
+
26
+ ```python
27
+ from buildaquery.abstract_syntax_tree.models import SelectStatementNode, ColumnNode, TableNode
28
+
29
+ # SELECT * FROM users
30
+ query = SelectStatementNode(
31
+ select_list=[ColumnNode(name="*")],
32
+ from_table=TableNode(name="users")
33
+ )
34
+ ```
35
+
36
+ This tree can then be processed by visitors (see the `traversal` module) for compilation or analysis.
37
+
38
+ ## TODOs
39
+
40
+ To make the AST more robust and capable of representing the full scope of the SQL language, the following enhancements are planned:
41
+
42
+ - **DML Support**:
43
+ - [x] Implement `InsertStatementNode` and `UpdateStatementNode`.
44
+ - [x] Implement `DeleteStatementNode`.
45
+ - **Advanced Query Features**:
46
+ - [x] **CTEs**: Add `WithClauseNode` for common table expressions.
47
+ - [x] **Set Operations**: Implement `UnionNode`, `IntersectNode`, and `ExceptNode`.
48
+ - [x] **DISTINCT**: Add support for `SELECT DISTINCT`.
49
+ - **Richer Expression Logic**:
50
+ - **Specialized Expressions**: Add [x] `CaseExpressionNode`, [x] `InNode`, and [x] `BetweenNode`.
51
+ - [x] **Subqueries**: Enable `SelectStatementNode` to be used within expressions.
52
+ - [x] **Window Functions**: Support `OVER` clauses and partitioning.
53
+ - [x] **Schema & Namespacing**: Update `TableNode` and `ColumnNode` to support qualified names (e.g., `schema.table`) and add a `CastNode` for type casting.
54
+ - **DDL Support**: [x] Add nodes for `CREATE`, `ALTER`, and `DROP` statements for schema management.
@@ -0,0 +1 @@
1
+ from .models import *
@@ -0,0 +1,285 @@
1
+ from abc import ABC
2
+ from dataclasses import dataclass
3
+ from typing import Any
4
+
5
+ # ==================================================
6
+ # Base classes
7
+ # ==================================================
8
+ @dataclass
9
+ class ASTNode(ABC):
10
+ """
11
+ A generic AST node. All specific AST node types will inherit from this base class.
12
+ """
13
+ pass
14
+
15
+ @dataclass
16
+ class ExpressionNode(ASTNode):
17
+ """
18
+ A base class for all expression nodes in the AST.
19
+ """
20
+ pass
21
+
22
+ # ==================================================
23
+ # Specific expression nodes
24
+ # ==================================================
25
+
26
+ @dataclass
27
+ class LiteralNode(ExpressionNode):
28
+ """
29
+ Represents a literal value in the AST, such as a number or string.
30
+ """
31
+ value: Any
32
+
33
+ @dataclass
34
+ class ColumnNode(ExpressionNode):
35
+ """
36
+ Represents a column reference in the AST.
37
+ """
38
+ name: str
39
+ table: str | None = None
40
+
41
+ @dataclass
42
+ class BinaryOperationNode(ExpressionNode):
43
+ """
44
+ Represents a binary operation in the AST, such as addition, subtraction, etc.
45
+ """
46
+ left: ExpressionNode
47
+ operator: str
48
+ right: ExpressionNode
49
+
50
+ # ==================================================
51
+ # Statement nodes
52
+ # ==================================================
53
+
54
+ @dataclass
55
+ class StatementNode(ASTNode):
56
+ """
57
+ A base class for all statement nodes in the AST.
58
+ """
59
+ pass
60
+
61
+ @dataclass
62
+ class FromClauseNode(ASTNode):
63
+ """
64
+ Represents a FROM clause in the AST, anything can appears here, including subqueries, joins, etc.
65
+ """
66
+ pass
67
+
68
+ @dataclass
69
+ class SubqueryNode(ExpressionNode, FromClauseNode):
70
+ """
71
+ Represents a subquery that can be used in an expression or a FROM clause.
72
+ """
73
+ statement: 'SelectStatementNode'
74
+ alias: str | None = None
75
+
76
+ @dataclass
77
+ class JoinClauseNode(FromClauseNode):
78
+ """
79
+ Represents a JOIN clause in the AST.
80
+ """
81
+ left: FromClauseNode
82
+ right: FromClauseNode
83
+ on_condition: ExpressionNode
84
+ join_type: str
85
+
86
+ @dataclass
87
+ class OrderByClauseNode(ASTNode):
88
+ """
89
+ Represents a single item in the ORDER BY clause in the AST.
90
+ """
91
+ expression: ExpressionNode
92
+ direction: str = "ASC" # default to ascending order
93
+
94
+ @dataclass
95
+ class TopClauseNode(ASTNode):
96
+ """
97
+ Represents a TOP clause in the AST.
98
+ """
99
+ count: int
100
+ # Optional: Column to order by for TOP clause, if not already specified in ORDER BY
101
+ on_expression: ExpressionNode | None = None
102
+ direction: str = "DESC" # default to descending order for TOP
103
+
104
+ @dataclass
105
+ class TableNode(FromClauseNode):
106
+ """
107
+ Represents a table reference in the AST.
108
+ """
109
+ name: str
110
+ schema: str | None = None
111
+ alias: str | None = None
112
+
113
+ @dataclass
114
+ class AliasNode(ExpressionNode):
115
+ """Represents an aliased expression (e.g., 'column AS new_name')."""
116
+ expression: ExpressionNode
117
+ name: str
118
+
119
+ @dataclass
120
+ class OverClauseNode(ASTNode):
121
+ """Represents an OVER clause for window functions."""
122
+ partition_by: list[ExpressionNode] | None = None
123
+ order_by: list[OrderByClauseNode] | None = None
124
+
125
+ @dataclass
126
+ class CastNode(ExpressionNode):
127
+ """Represents a type cast (e.g., 'CAST(column AS type)' or 'column::type')."""
128
+ expression: ExpressionNode
129
+ data_type: str
130
+
131
+ @dataclass
132
+ class FunctionCallNode(ExpressionNode):
133
+ """Represents a function call (e.g., COUNT(*), MAX(price))."""
134
+ name: str
135
+ args: list[ExpressionNode]
136
+ over: OverClauseNode | None = None # optional OVER clause for window functions
137
+
138
+ @dataclass
139
+ class UnaryOperationNode(ExpressionNode):
140
+ """Represents a unary operation (e.g., NOT, -)."""
141
+ operator: str
142
+ operand: ExpressionNode
143
+
144
+ @dataclass
145
+ class InNode(ExpressionNode):
146
+ """Represents an IN expression (e.g., 'column IN (1, 2, 3)')."""
147
+ expression: ExpressionNode
148
+ values: list[ExpressionNode]
149
+ negated: bool = False
150
+
151
+ @dataclass
152
+ class WhenThenNode(ASTNode):
153
+ """Represents a WHEN ... THEN ... clause in a CASE expression."""
154
+ condition: ExpressionNode
155
+ result: ExpressionNode
156
+
157
+ @dataclass
158
+ class CaseExpressionNode(ExpressionNode):
159
+ """Represents a CASE expression (e.g., 'CASE WHEN cond THEN res ELSE default END')."""
160
+ cases: list[WhenThenNode]
161
+ else_result: ExpressionNode | None = None
162
+
163
+ @dataclass
164
+ class BetweenNode(ExpressionNode):
165
+ """Represents a BETWEEN expression (e.g., 'column BETWEEN 1 AND 10')."""
166
+ expression: ExpressionNode
167
+ low: ExpressionNode
168
+ high: ExpressionNode
169
+ negated: bool = False
170
+
171
+ @dataclass
172
+ class StarNode(ExpressionNode):
173
+ """Represents the '*' in 'SELECT *'."""
174
+ pass
175
+
176
+ @dataclass
177
+ class WhereClauseNode(ASTNode):
178
+ """A wrapper for the expression in a WHERE clause."""
179
+ condition: ExpressionNode
180
+
181
+ @dataclass
182
+ class GroupByClauseNode(ASTNode):
183
+ """A wrapper for the list of expressions in a GROUP BY clause."""
184
+ expressions: list[ExpressionNode]
185
+
186
+ @dataclass
187
+ class HavingClauseNode(ASTNode):
188
+ """A wrapper for the expression in a HAVING clause."""
189
+ condition: ExpressionNode
190
+
191
+ @dataclass
192
+ class CTENode(ASTNode):
193
+ """Represents a Common Table Expression (WITH clause)."""
194
+ name: str
195
+ subquery: 'SelectStatementNode'
196
+
197
+ @dataclass
198
+ class SelectStatementNode(StatementNode):
199
+ """
200
+ Represents a SELECT statement in the AST.
201
+ """
202
+ select_list: list[ExpressionNode] # list of expressions to select (eg: columns, functions, etc.)
203
+ distinct: bool = False # toggle between SELECT ALL and SELECT DISTINCT
204
+ ctes: list[CTENode] | None = None # optional list of Common Table Expressions
205
+ from_table: FromClauseNode | None = None # the table to select from, optional for edge cases
206
+ where_clause: WhereClauseNode | None = None # optional where clause for filtering results
207
+ group_by: GroupByClauseNode | None = None # optional group by clause for aggregation
208
+ having_clause: HavingClauseNode | None = None # optional having clause for filtering groups in aggregation
209
+ order_by_clause: list[OrderByClauseNode] | None = None # optional list of order by clauses for sorting results
210
+ top_clause: TopClauseNode | None = None # optional top clause, mutually exclusive with limit and offset
211
+ limit: int | None = None # optional limit for number of results to return
212
+ offset: int | None = None # optional offset for skipping results
213
+
214
+ @dataclass
215
+ class DeleteStatementNode(StatementNode):
216
+ """
217
+ Represents a DELETE statement in the AST.
218
+ """
219
+ table: TableNode
220
+ where_clause: WhereClauseNode | None = None
221
+
222
+ @dataclass
223
+ class ColumnDefinitionNode(ASTNode):
224
+ """Represents a column definition in a CREATE TABLE statement."""
225
+ name: str
226
+ data_type: str
227
+ primary_key: bool = False
228
+ not_null: bool = False
229
+ default: ExpressionNode | None = None
230
+
231
+ @dataclass
232
+ class CreateStatementNode(StatementNode):
233
+ """Represents a CREATE TABLE statement."""
234
+ table: TableNode
235
+ columns: list[ColumnDefinitionNode]
236
+ if_not_exists: bool = False
237
+
238
+ @dataclass
239
+ class DropStatementNode(StatementNode):
240
+ """Represents a DROP TABLE statement."""
241
+ table: TableNode
242
+ if_exists: bool = False
243
+ cascade: bool = False
244
+
245
+ @dataclass
246
+ class InsertStatementNode(StatementNode):
247
+ """
248
+ Represents an INSERT statement in the AST.
249
+ """
250
+ table: TableNode
251
+ values: list[ExpressionNode]
252
+ columns: list[ColumnNode] | None = None
253
+
254
+ @dataclass
255
+ class UpdateStatementNode(StatementNode):
256
+ """
257
+ Represents an UPDATE statement in the AST.
258
+ """
259
+ table: TableNode
260
+ set_clauses: dict[str, ExpressionNode] # Map column names to new values/expressions
261
+ where_clause: WhereClauseNode | None = None
262
+
263
+ @dataclass
264
+ class SetOperationNode(StatementNode):
265
+ """
266
+ Base class for set operations like UNION, INTERSECT, EXCEPT.
267
+ """
268
+ left: StatementNode
269
+ right: StatementNode
270
+ all: bool = False
271
+
272
+ @dataclass
273
+ class UnionNode(SetOperationNode):
274
+ """Represents a UNION operation."""
275
+ pass
276
+
277
+ @dataclass
278
+ class IntersectNode(SetOperationNode):
279
+ """Represents an INTERSECT operation."""
280
+ pass
281
+
282
+ @dataclass
283
+ class ExceptNode(SetOperationNode):
284
+ """Represents an EXCEPT operation."""
285
+ pass
@@ -0,0 +1,48 @@
1
+ # Compiler
2
+
3
+ The `compiler` module is responsible for translating the dialect-agnostic Abstract Syntax Tree (AST) into specific SQL dialects.
4
+
5
+ ## Core Concepts
6
+
7
+ ### `CompiledQuery` Dataclass
8
+ Every compiler returns a `CompiledQuery` object instead of a raw string. This ensures that queries are handled safely and consistently.
9
+
10
+ - **`sql` (str)**: The SQL query string containing placeholders (e.g., `%s` for PostgreSQL).
11
+ - **`params` (list[Any])**: A list of values corresponding to the placeholders in the SQL string.
12
+
13
+ ### Parametrization
14
+ To prevent SQL injection, the compilers are designed to automatically parametrize all literal values. When a `LiteralNode` is encountered, the compiler:
15
+ 1. Appends a placeholder to the SQL string.
16
+ 2. Appends the literal value to the `params` list.
17
+
18
+ ## Implementations
19
+
20
+ ### PostgreSQL (`PostgresCompiler`)
21
+ The initial implementation supports PostgreSQL.
22
+
23
+ #### Key Features:
24
+ - **DISTINCT Support**: Handles `SELECT DISTINCT` queries.
25
+ - **DML Support**: Supports `INSERT`, `UPDATE`, and `DELETE` operations.
26
+ - **Set Operations**: Support for `UNION`, `INTERSECT`, and `EXCEPT` (including `ALL`).
27
+ - **CTEs**: Support for `WITH` clauses.
28
+ - **Specialized Expressions**: Support for `IN`, `BETWEEN`, and `CASE`.
29
+ - **Subqueries**: Support for subqueries in `FROM` and `WHERE` clauses.
30
+ - **Window Functions**: Support for `OVER` clauses, `PARTITION BY`, and `ORDER BY`.
31
+ - **DDL Support**: Support for `CREATE TABLE` and `DROP TABLE`.
32
+ - **Qualified Names**: Supports `schema.table` and `table.column` naming conventions.
33
+ - **Type Casting**: Supports `CAST(expression AS type)`.
34
+ - **Clause Ordering**: Ensures `SELECT`, `FROM`, `WHERE`, `GROUP BY`, `HAVING`, `ORDER BY`, and `LIMIT` are placed in the correct sequence.
35
+ - **TOP Translation**: Automatically translates `TopClauseNode` into PostgreSQL-compliant `LIMIT` and `ORDER BY` logic.
36
+ - **Mutual Exclusivity Enforcement**: Raises a `ValueError` if a query attempts to use both `TOP` and standard `LIMIT/OFFSET`.
37
+
38
+ ## Usage Example
39
+
40
+ ```python
41
+ from buildaquery.compiler.postgres.postgres_compiler import PostgresCompiler
42
+
43
+ compiler = PostgresCompiler()
44
+ compiled = compiler.compile(ast_root)
45
+
46
+ print(compiled.sql) # "SELECT * FROM users WHERE id = %s"
47
+ print(compiled.params) # [123]
48
+ ```
File without changes
@@ -0,0 +1,25 @@
1
+ # PostgreSQL Compiler
2
+
3
+ This sub-module provides the concrete implementation of the SQL compiler for PostgreSQL.
4
+
5
+ ## Features
6
+
7
+ - **Standard DML Support**: Compiles `SELECT`, `INSERT`, `UPDATE`, and `DELETE` statements.
8
+ - **Set Operations**: Supports `UNION`, `INTERSECT`, and `EXCEPT` (and their `ALL` variants).
9
+ - **CTEs**: Supports Common Table Expressions (`WITH` clause).
10
+ - **Specialized Expressions**: Supports `IN`, `BETWEEN`, and `CASE` operators.
11
+ - **Subqueries**: Handles subqueries in `FROM` and `WHERE` clauses.
12
+ - **Window Functions**: Supports window functions with `OVER`, `PARTITION BY`, and `ORDER BY`.
13
+ - **DDL Support**: Handles `CREATE TABLE` and `DROP TABLE` statements.
14
+ - **DISTINCT**: Supports `SELECT DISTINCT`.
15
+ - **Qualified Names**: Handles `schema.table` and `table.column` identifiers.
16
+ - **Type Casting**: Supports `CAST(expression AS type)`.
17
+ - **Filtering**: Translates `WhereClauseNode` and complex binary/unary operations.
18
+ - **Parametrization**: Automatically uses `%s` placeholders for all literal values to ensure security.
19
+ - **Dialect Specifics**:
20
+ - Translates `TopClauseNode` into a combination of `LIMIT` and `ORDER BY`.
21
+ - Handles PostgreSQL-specific operator precedence through grouping.
22
+
23
+ ## Implementation Details
24
+
25
+ The compiler is implemented as a `Visitor` that recursively traverses the AST. For expression nodes, it generally follows a post-order traversal to build the SQL string from the bottom up.