@xano/developer-mcp 1.0.9 → 1.0.10
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.
- package/package.json +1 -1
- package/xanoscript_docs/addons.md +57 -86
package/package.json
CHANGED
|
@@ -9,15 +9,16 @@ Reusable subqueries for fetching related data in database queries.
|
|
|
9
9
|
## Quick Reference
|
|
10
10
|
|
|
11
11
|
```xs
|
|
12
|
-
addon
|
|
13
|
-
description = "What this addon fetches"
|
|
12
|
+
addon <name> {
|
|
14
13
|
input {
|
|
15
14
|
<type> <name>
|
|
16
15
|
}
|
|
16
|
+
|
|
17
17
|
stack {
|
|
18
|
-
|
|
18
|
+
db.query <tableName> {
|
|
19
|
+
return = {type: "<return_type>"}
|
|
20
|
+
}
|
|
19
21
|
}
|
|
20
|
-
response = $result
|
|
21
22
|
}
|
|
22
23
|
```
|
|
23
24
|
|
|
@@ -25,21 +26,20 @@ addon "<name>" {
|
|
|
25
26
|
|
|
26
27
|
## Basic Structure
|
|
27
28
|
|
|
28
|
-
Addons define reusable data fetching logic that can be attached to query results.
|
|
29
|
+
Addons define reusable data fetching logic that can be attached to query results. The stack can only contain a `db.query` block.
|
|
29
30
|
|
|
30
31
|
```xs
|
|
31
|
-
addon
|
|
32
|
-
description = "Count of comments for a post"
|
|
32
|
+
addon comment_count {
|
|
33
33
|
input {
|
|
34
34
|
int post_id
|
|
35
35
|
}
|
|
36
|
+
|
|
36
37
|
stack {
|
|
37
|
-
db.query
|
|
38
|
+
db.query comment {
|
|
38
39
|
where = $db.comment.post_id == $input.post_id
|
|
39
|
-
return = {
|
|
40
|
-
}
|
|
40
|
+
return = {type: "count"}
|
|
41
|
+
}
|
|
41
42
|
}
|
|
42
|
-
response = $count
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
@@ -50,12 +50,12 @@ addon "comment_count" {
|
|
|
50
50
|
### In db.query
|
|
51
51
|
|
|
52
52
|
```xs
|
|
53
|
-
db.query
|
|
53
|
+
db.query post {
|
|
54
54
|
where = $db.post.author_id == $auth.id
|
|
55
55
|
addon = [
|
|
56
56
|
{
|
|
57
57
|
name: "comment_count",
|
|
58
|
-
input: {
|
|
58
|
+
input: {post_id: $output.id},
|
|
59
59
|
as: "items.comment_count"
|
|
60
60
|
}
|
|
61
61
|
]
|
|
@@ -79,22 +79,22 @@ db.query "post" {
|
|
|
79
79
|
### Multiple Addons
|
|
80
80
|
|
|
81
81
|
```xs
|
|
82
|
-
db.query
|
|
82
|
+
db.query post {
|
|
83
83
|
where = $db.post.is_published == true
|
|
84
84
|
addon = [
|
|
85
85
|
{
|
|
86
86
|
name: "comment_count",
|
|
87
|
-
input: {
|
|
87
|
+
input: {post_id: $output.id},
|
|
88
88
|
as: "items.comments"
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
name: "like_count",
|
|
92
|
-
input: {
|
|
92
|
+
input: {post_id: $output.id},
|
|
93
93
|
as: "items.likes"
|
|
94
94
|
},
|
|
95
95
|
{
|
|
96
96
|
name: "author_details",
|
|
97
|
-
input: {
|
|
97
|
+
input: {user_id: $output.author_id},
|
|
98
98
|
as: "items.author"
|
|
99
99
|
}
|
|
100
100
|
]
|
|
@@ -108,103 +108,75 @@ db.query "post" {
|
|
|
108
108
|
### Related List
|
|
109
109
|
|
|
110
110
|
```xs
|
|
111
|
-
addon
|
|
112
|
-
description = "Get recent comments for a post"
|
|
111
|
+
addon recent_comments {
|
|
113
112
|
input {
|
|
114
113
|
int post_id
|
|
115
114
|
int limit?=5
|
|
116
115
|
}
|
|
116
|
+
|
|
117
117
|
stack {
|
|
118
|
-
db.query
|
|
118
|
+
db.query comment {
|
|
119
119
|
where = $db.comment.post_id == $input.post_id
|
|
120
|
-
sort = {
|
|
120
|
+
sort = {created_at: "desc"}
|
|
121
121
|
return = {
|
|
122
122
|
type: "list",
|
|
123
|
-
paging: {
|
|
123
|
+
paging: {per_page: $input.limit}
|
|
124
124
|
}
|
|
125
|
-
}
|
|
125
|
+
}
|
|
126
126
|
}
|
|
127
|
-
response = $comments.items
|
|
128
127
|
}
|
|
129
128
|
```
|
|
130
129
|
|
|
131
|
-
###
|
|
130
|
+
### Count
|
|
132
131
|
|
|
133
132
|
```xs
|
|
134
|
-
addon
|
|
135
|
-
description = "Order statistics for a user"
|
|
133
|
+
addon order_count {
|
|
136
134
|
input {
|
|
137
135
|
int user_id
|
|
138
136
|
}
|
|
137
|
+
|
|
139
138
|
stack {
|
|
140
|
-
db.query
|
|
139
|
+
db.query order {
|
|
141
140
|
where = $db.order.user_id == $input.user_id
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
var $stats {
|
|
145
|
-
value = {
|
|
146
|
-
total_orders: $orders|count,
|
|
147
|
-
total_spent: $orders|map:$$.total|sum,
|
|
148
|
-
avg_order: $orders|map:$$.total|avg
|
|
149
|
-
}
|
|
141
|
+
return = {type: "count"}
|
|
150
142
|
}
|
|
151
143
|
}
|
|
152
|
-
response = $stats
|
|
153
144
|
}
|
|
154
145
|
```
|
|
155
146
|
|
|
156
|
-
###
|
|
147
|
+
### Boolean Check (Exists)
|
|
157
148
|
|
|
158
149
|
```xs
|
|
159
|
-
addon
|
|
160
|
-
description = "Get formatted address for a user"
|
|
150
|
+
addon has_premium {
|
|
161
151
|
input {
|
|
162
152
|
int user_id
|
|
163
153
|
}
|
|
154
|
+
|
|
164
155
|
stack {
|
|
165
|
-
db.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
conditional {
|
|
171
|
-
if ($address != null) {
|
|
172
|
-
var $formatted {
|
|
173
|
-
value = {
|
|
174
|
-
street: $address.street,
|
|
175
|
-
city: $address.city,
|
|
176
|
-
state: $address.state,
|
|
177
|
-
zip: $address.zip,
|
|
178
|
-
full: $address.street ~ ", " ~ $address.city ~ ", " ~ $address.state ~ " " ~ $address.zip
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
var $formatted { value = null }
|
|
184
|
-
}
|
|
156
|
+
db.query subscription {
|
|
157
|
+
where = $db.subscription.user_id == $input.user_id
|
|
158
|
+
&& $db.subscription.status == "active"
|
|
159
|
+
&& $db.subscription.expires_at > now
|
|
160
|
+
return = {type: "exists"}
|
|
185
161
|
}
|
|
186
162
|
}
|
|
187
|
-
response = $formatted
|
|
188
163
|
}
|
|
189
164
|
```
|
|
190
165
|
|
|
191
|
-
###
|
|
166
|
+
### Single Record
|
|
192
167
|
|
|
193
168
|
```xs
|
|
194
|
-
addon
|
|
195
|
-
description = "Check if user has premium subscription"
|
|
169
|
+
addon author_details {
|
|
196
170
|
input {
|
|
197
171
|
int user_id
|
|
198
172
|
}
|
|
173
|
+
|
|
199
174
|
stack {
|
|
200
|
-
db.query
|
|
201
|
-
where = $db.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return = { type: "exists" }
|
|
205
|
-
} as $has_premium
|
|
175
|
+
db.query user {
|
|
176
|
+
where = $db.user.id == $input.user_id
|
|
177
|
+
return = {type: "single"}
|
|
178
|
+
}
|
|
206
179
|
}
|
|
207
|
-
response = $has_premium
|
|
208
180
|
}
|
|
209
181
|
```
|
|
210
182
|
|
|
@@ -215,8 +187,8 @@ addon "has_premium" {
|
|
|
215
187
|
Call an addon directly from a function or API.
|
|
216
188
|
|
|
217
189
|
```xs
|
|
218
|
-
addon.call
|
|
219
|
-
input = {
|
|
190
|
+
addon.call comment_count {
|
|
191
|
+
input = {post_id: $input.post_id}
|
|
220
192
|
} as $count
|
|
221
193
|
```
|
|
222
194
|
|
|
@@ -224,16 +196,16 @@ addon.call "comment_count" {
|
|
|
224
196
|
|
|
225
197
|
```xs
|
|
226
198
|
// Get stats for single record
|
|
227
|
-
addon.call
|
|
228
|
-
input = {
|
|
229
|
-
} as $
|
|
199
|
+
addon.call order_count {
|
|
200
|
+
input = {user_id: $auth.id}
|
|
201
|
+
} as $my_order_count
|
|
230
202
|
|
|
231
203
|
// Conditional addon call
|
|
232
204
|
conditional {
|
|
233
205
|
if ($input.include_stats) {
|
|
234
|
-
addon.call
|
|
235
|
-
input = {
|
|
236
|
-
} as $
|
|
206
|
+
addon.call order_count {
|
|
207
|
+
input = {user_id: $entity.id}
|
|
208
|
+
} as $count
|
|
237
209
|
}
|
|
238
210
|
}
|
|
239
211
|
```
|
|
@@ -245,9 +217,9 @@ conditional {
|
|
|
245
217
|
Use `dbAddonAttr` for computed fields in queries.
|
|
246
218
|
|
|
247
219
|
```xs
|
|
248
|
-
db.query
|
|
220
|
+
db.query product {
|
|
249
221
|
eval = {
|
|
250
|
-
discount_price: dbAddonAttr("calculate_discount", {
|
|
222
|
+
discount_price: dbAddonAttr("calculate_discount", {product_id: $db.product.id})
|
|
251
223
|
}
|
|
252
224
|
} as $products
|
|
253
225
|
```
|
|
@@ -263,7 +235,7 @@ addons/
|
|
|
263
235
|
├── comment_count.xs
|
|
264
236
|
├── like_count.xs
|
|
265
237
|
├── author_details.xs
|
|
266
|
-
├──
|
|
238
|
+
├── order_count.xs
|
|
267
239
|
└── has_premium.xs
|
|
268
240
|
```
|
|
269
241
|
|
|
@@ -279,7 +251,6 @@ addons/
|
|
|
279
251
|
|
|
280
252
|
1. **Keep addons focused** - One purpose per addon
|
|
281
253
|
2. **Use input parameters** - Make addons reusable
|
|
282
|
-
3. **
|
|
283
|
-
4. **
|
|
284
|
-
5. **
|
|
285
|
-
6. **Document inputs** - Add descriptions to input fields
|
|
254
|
+
3. **Use appropriate return types** - `list`, `single`, `count`, `exists`
|
|
255
|
+
4. **Limit nested queries** - Avoid N+1 query patterns
|
|
256
|
+
5. **Document inputs** - Add descriptions to input fields
|