1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/// this the py_sql syntax tree
use crateBindNode;
use crateBreakNode;
use crateChooseNode;
use crateContinueNode;
use crateForEachNode;
use crateIfNode;
use crateOtherwiseNode;
use crateSetNode;
use crateSqlNode;
use crateStringNode;
use crateTrimNode;
use crateWhenNode;
use crateWhereNode;
/// PySQL Syntax Tree
///
/// The syntax of PySQL is based on Python-like indentation and line structure.
/// Each node type below represents a different structure in the PySQL language.
///
/// Syntax Rules:
///
/// 1. Nodes that define a block end with a colon ':' and their children are indented.
///
/// 2. `NString` - Plain text or SQL fragments. Can preserve whitespace with backticks:
/// ```sql
/// SELECT * FROM users
/// ` SELECT column1, column2 FROM table `
/// ```
///
/// 3. `NIf` - Conditional execution, similar to Python's if statement:
/// ```pysql
/// if condition:
/// SQL fragment
/// ```
///
/// 4. `NTrim` - Removes specified characters from start/end of the content:
/// ```pysql
/// trim ',': # Removes ',' from both start and end
/// trim start=',',end=')': # Removes ',' from start and ')' from end
/// ```
///
/// 5. `NForEach` - Iterates over collections:
/// ```pysql
/// for item in items: # Simple iteration
/// #{item}
/// for key,item in items: # With key/index
/// #{key}: #{item}
/// ```
///
/// 6. `NChoose`/`NWhen`/`NOtherwise` - Switch-like structure:
/// ```pysql
/// choose:
/// when condition1:
/// SQL fragment 1
/// when condition2:
/// SQL fragment 2
/// otherwise: # Or use '_:'
/// Default SQL fragment
/// ```
///
/// 7. `NBind` - Variable binding:
/// ```pysql
/// bind name = 'value': # Or use 'let name = value:'
/// SQL using #{name}
/// ```
///
/// 8. `NSet` - For UPDATE statements, handles comma separation.
/// It can also define a collection to iterate over for generating SET clauses.
/// ```pysql
/// // Simple set for direct updates
/// set:
/// if name != null:
/// name = #{name},
/// if age != null:
/// age = #{age}
///
/// // Set with collection to iterate (e.g., from a map or struct)
/// // Assuming 'user_updates' is a map like {'name': 'new_name', 'status': 'active'}
/// set collection="user_updates" skips="id,created_at" skip_null="true":
/// // This will generate: name = #{user_updates.name}, status = #{user_updates.status}
/// // 'id' and 'created_at' fields from 'user_updates' will be skipped.
/// // If a value in 'user_updates' is null and skip_null is true, it will be skipped.
/// ```
///
/// 9. `NWhere` - For WHERE clauses, handles AND/OR prefixes:
/// ```pysql
/// where:
/// if id != null:
/// AND id = #{id}
/// if name != null:
/// AND name = #{name}
/// ```
///
/// 10. `NContinue`/`NBreak` - Loop control, must be inside a for loop:
/// ```pysql
/// for item in items:
/// if item == null:
/// break:
/// if item == 0:
/// continue:
/// ```
///
/// 11. `NSql` - Reusable SQL fragments with an ID:
/// ```pysql
/// sql id='userColumns':
/// id, name, age
/// ```
///
/// Note: All control nodes require a colon at the end, and their child content
/// must be indented with more spaces than the parent node.
/// the node name
/// node default name
/// Convert syntax tree to HTML deconstruction