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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
use TokenStream;
use quote;
use ;
use crateSqlQuery;
/// Builds a type-safe QuickBooks Online query at compile time.
///
/// This macro parses SQL-like syntax and generates a `Query<T>` struct that can be used to query
/// the QuickBooks Online API. Field names are automatically validated at compile time and converted
/// from snake_case to CamelCase to match QuickBooks naming conventions.
///
/// # Syntax
///
/// ```text
/// qb_sql!(
/// select [* | field1, field2, ...]
/// from EntityType
/// [where condition [and condition ...]]
/// [order by field [asc|desc] [, field [asc|desc] ...]]
/// [limit number [offset number]]
/// )
/// ```
///
/// # Supported Operators
///
/// - `=` - Equality comparison
/// - `>`, `<`, `>=`, `<=` - Numeric comparisons
/// - `like` - Pattern matching (use `%` as wildcard)
/// - `in` - Match against multiple values: `field in (val1, val2, ...)` or `field in (iterator)`
///
/// # Examples
///
/// Basic query with field selection:
/// ```ignore
/// use quick_oxibooks_sql::qb_sql;
/// use quickbooks_types::Customer;
///
/// let query = qb_sql!(
/// select display_name, balance from Customer
/// where balance >= 1000.0
/// order by display_name asc
/// limit 10
/// );
/// ```
///
/// Using Rust variables in conditions:
/// ```ignore
/// let min_balance = 500.0;
/// let name_pattern = "Acme%";
///
/// let query = qb_sql!(
/// select * from Customer
/// where balance >= min_balance
/// and display_name like name_pattern
/// );
/// ```
///
/// Using the `in` operator with a tuple or iterator:
/// ```ignore
/// // With literal values
/// let query = qb_sql!(
/// select * from Customer
/// where id in (1, 2, 3)
/// );
///
/// // With an iterator (single expression)
/// let ids = vec!["1", "2", "3"];
/// let query = qb_sql!(
/// select * from Customer
/// where id in (ids)
/// );
/// ```
///
/// Executing a query (requires the `api` feature):
/// ```ignore
/// use quick_oxibooks::{Environment, QBContext};
/// use ureq::Agent;
///
/// let client = Agent::new();
/// let qb = QBContext::new(Environment::SANDBOX, "company_id".into(), "token".into(), &client)?;
///
/// let results = query.execute(&qb, &client)?;
/// ```
///
/// # Notes
///
/// - Field names are automatically converted from snake_case to CamelCase (e.g., `display_name` → `DisplayName`)
/// - All field names are validated at compile time against the entity type
/// - The generated query can be converted to a string with `.query_string()` or by displaying it
/// - For the `in` operator, use a tuple for literals or a single iterator expression
/// Represents a ExprField that is type checked with options for nested fields
///
/// At least one field is required, and additional fields can be chained using dot notation.
/// For example: `field1.field2.field3`
;
// Type Check for OptionExprField
// Custom keywords