@xano/developer-mcp 1.0.1 → 1.0.2
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/README.md +96 -31
- package/dist/index.js +248 -180
- package/package.json +4 -2
- package/xanoscript_docs/README.md +107 -1
- package/xanoscript_docs/agents.md +329 -0
- package/xanoscript_docs/apis.md +343 -0
- package/xanoscript_docs/database.md +417 -0
- package/xanoscript_docs/ephemeral.md +333 -0
- package/xanoscript_docs/frontend.md +291 -0
- package/xanoscript_docs/functions.md +232 -2035
- package/xanoscript_docs/integrations.md +439 -0
- package/xanoscript_docs/mcp-servers.md +190 -0
- package/xanoscript_docs/plan.md +192 -0
- package/xanoscript_docs/syntax.md +314 -0
- package/xanoscript_docs/tables.md +270 -0
- package/xanoscript_docs/tasks.md +254 -0
- package/xanoscript_docs/testing.md +335 -0
- package/xanoscript_docs/tools.md +305 -0
- package/xanoscript_docs/types.md +297 -0
- package/xanoscript_docs/version.json +2 -1
- package/xanoscript_docs/api_query_examples.md +0 -1255
- package/xanoscript_docs/api_query_guideline.md +0 -129
- package/xanoscript_docs/build_from_lovable.md +0 -715
- package/xanoscript_docs/db_query_guideline.md +0 -427
- package/xanoscript_docs/ephemeral_environment_guideline.md +0 -529
- package/xanoscript_docs/expression_guideline.md +0 -1086
- package/xanoscript_docs/frontend_guideline.md +0 -67
- package/xanoscript_docs/function_examples.md +0 -1406
- package/xanoscript_docs/function_guideline.md +0 -130
- package/xanoscript_docs/input_guideline.md +0 -227
- package/xanoscript_docs/mcp_server_examples.md +0 -36
- package/xanoscript_docs/mcp_server_guideline.md +0 -69
- package/xanoscript_docs/query_filter.md +0 -489
- package/xanoscript_docs/table_examples.md +0 -586
- package/xanoscript_docs/table_guideline.md +0 -137
- package/xanoscript_docs/task_examples.md +0 -511
- package/xanoscript_docs/task_guideline.md +0 -103
- package/xanoscript_docs/tips_and_tricks.md +0 -144
- package/xanoscript_docs/tool_examples.md +0 -69
- package/xanoscript_docs/tool_guideline.md +0 -139
- package/xanoscript_docs/unit_testing_guideline.md +0 -328
- package/xanoscript_docs/workspace.md +0 -17
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "functions/**/*.xs, apis/**/*.xs, tasks/*.xs, tools/**/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Database Operations
|
|
6
|
+
|
|
7
|
+
Complete reference for XanoScript database operations.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
| Operation | Purpose | Returns |
|
|
12
|
+
|-----------|---------|---------|
|
|
13
|
+
| `db.query` | Query multiple records | List/single/count/exists |
|
|
14
|
+
| `db.get` | Get single record by field | Record or null |
|
|
15
|
+
| `db.has` | Check if record exists | Boolean |
|
|
16
|
+
| `db.add` | Insert new record | Created record |
|
|
17
|
+
| `db.edit` | Update record (inline data) | Updated record |
|
|
18
|
+
| `db.patch` | Update record (variable data) | Updated record |
|
|
19
|
+
| `db.add_or_edit` | Upsert record | Record |
|
|
20
|
+
| `db.del` | Delete record | None |
|
|
21
|
+
| `db.truncate` | Delete all records | None |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## db.query
|
|
26
|
+
|
|
27
|
+
Query multiple records with filters, sorting, and pagination.
|
|
28
|
+
|
|
29
|
+
### Basic Query
|
|
30
|
+
```xs
|
|
31
|
+
db.query "product" {
|
|
32
|
+
where = $db.product.is_active == true
|
|
33
|
+
} as $products
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Where Operators
|
|
37
|
+
```xs
|
|
38
|
+
# Comparison
|
|
39
|
+
$db.product.price == 100
|
|
40
|
+
$db.product.price != 0
|
|
41
|
+
$db.product.price > 50
|
|
42
|
+
$db.product.price >= 50
|
|
43
|
+
$db.product.price < 100
|
|
44
|
+
$db.product.price <= 100
|
|
45
|
+
|
|
46
|
+
# Null-safe (ignore if value is null)
|
|
47
|
+
$db.product.category ==? $input.category
|
|
48
|
+
$db.product.price >=? $input.min_price
|
|
49
|
+
|
|
50
|
+
# String matching
|
|
51
|
+
$db.product.name includes "phone" # Contains substring
|
|
52
|
+
$db.product.tags contains "featured" # Array contains value
|
|
53
|
+
$db.product.tags not contains "hidden"
|
|
54
|
+
|
|
55
|
+
# Array overlap
|
|
56
|
+
$db.product.tags overlaps ["a", "b"]
|
|
57
|
+
$db.product.tags not overlaps ["x", "y"]
|
|
58
|
+
|
|
59
|
+
# Combining conditions
|
|
60
|
+
$db.product.is_active == true && $db.product.price > 0
|
|
61
|
+
$db.product.category == "electronics" || $db.product.featured == true
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Return Types
|
|
65
|
+
```xs
|
|
66
|
+
# List (default)
|
|
67
|
+
db.query "product" {
|
|
68
|
+
return = { type: "list" }
|
|
69
|
+
} as $products
|
|
70
|
+
|
|
71
|
+
# With pagination
|
|
72
|
+
db.query "product" {
|
|
73
|
+
return = {
|
|
74
|
+
type: "list",
|
|
75
|
+
paging: { page: $input.page, per_page: 25, totals: true }
|
|
76
|
+
}
|
|
77
|
+
} as $products
|
|
78
|
+
|
|
79
|
+
# Single record
|
|
80
|
+
db.query "product" {
|
|
81
|
+
where = $db.product.sku == $input.sku
|
|
82
|
+
return = { type: "single" }
|
|
83
|
+
} as $product
|
|
84
|
+
|
|
85
|
+
# Count
|
|
86
|
+
db.query "product" {
|
|
87
|
+
where = $db.product.is_active == true
|
|
88
|
+
return = { type: "count" }
|
|
89
|
+
} as $count
|
|
90
|
+
|
|
91
|
+
# Exists
|
|
92
|
+
db.query "product" {
|
|
93
|
+
where = $db.product.email == $input.email
|
|
94
|
+
return = { type: "exists" }
|
|
95
|
+
} as $exists
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Sorting
|
|
99
|
+
```xs
|
|
100
|
+
db.query "product" {
|
|
101
|
+
sort = { created_at: "desc" } # Descending
|
|
102
|
+
sort = { name: "asc" } # Ascending
|
|
103
|
+
sort = { id: "rand" } # Random
|
|
104
|
+
} as $products
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Joins
|
|
108
|
+
```xs
|
|
109
|
+
db.query "comment" {
|
|
110
|
+
join = {
|
|
111
|
+
post: {
|
|
112
|
+
table: "post",
|
|
113
|
+
type: "inner", # inner, left, right
|
|
114
|
+
where: $db.comment.post_id == $db.post.id
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
where = $db.post.author_id == $auth.id
|
|
118
|
+
} as $comments
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Eval (Computed Fields)
|
|
122
|
+
```xs
|
|
123
|
+
db.query "order" {
|
|
124
|
+
join = {
|
|
125
|
+
user: { table: "user", where: $db.order.user_id == $db.user.id }
|
|
126
|
+
}
|
|
127
|
+
eval = {
|
|
128
|
+
user_name: $db.user.name,
|
|
129
|
+
user_email: $db.user.email
|
|
130
|
+
}
|
|
131
|
+
} as $orders
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Addons (Related Data)
|
|
135
|
+
```xs
|
|
136
|
+
db.query "post" {
|
|
137
|
+
where = $db.post.author_id == $auth.id
|
|
138
|
+
addon = [
|
|
139
|
+
{ name: "comment_count", input: { post_id: $output.id }, as: "items.comments" }
|
|
140
|
+
]
|
|
141
|
+
} as $posts
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## db.get
|
|
147
|
+
|
|
148
|
+
Get a single record by field value.
|
|
149
|
+
|
|
150
|
+
```xs
|
|
151
|
+
db.get "user" {
|
|
152
|
+
field_name = "id"
|
|
153
|
+
field_value = $input.user_id
|
|
154
|
+
} as $user
|
|
155
|
+
|
|
156
|
+
db.get "user" {
|
|
157
|
+
field_name = "email"
|
|
158
|
+
field_value = $input.email
|
|
159
|
+
} as $user
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## db.has
|
|
165
|
+
|
|
166
|
+
Check if a record exists.
|
|
167
|
+
|
|
168
|
+
```xs
|
|
169
|
+
db.has "user" {
|
|
170
|
+
field_name = "email"
|
|
171
|
+
field_value = $input.email
|
|
172
|
+
} as $exists
|
|
173
|
+
|
|
174
|
+
conditional {
|
|
175
|
+
if ($exists) {
|
|
176
|
+
throw { name = "DuplicateError", value = "Email already registered" }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## db.add
|
|
184
|
+
|
|
185
|
+
Insert a new record.
|
|
186
|
+
|
|
187
|
+
```xs
|
|
188
|
+
db.add "product" {
|
|
189
|
+
data = {
|
|
190
|
+
name: $input.name,
|
|
191
|
+
price: $input.price,
|
|
192
|
+
category_id: $input.category_id,
|
|
193
|
+
created_at: now
|
|
194
|
+
}
|
|
195
|
+
} as $product
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## db.edit
|
|
201
|
+
|
|
202
|
+
Update a record with inline data object.
|
|
203
|
+
|
|
204
|
+
```xs
|
|
205
|
+
db.edit "product" {
|
|
206
|
+
field_name = "id"
|
|
207
|
+
field_value = $input.product_id
|
|
208
|
+
data = {
|
|
209
|
+
name: $input.name,
|
|
210
|
+
price: $input.price,
|
|
211
|
+
updated_at: now
|
|
212
|
+
}
|
|
213
|
+
} as $product
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## db.patch
|
|
219
|
+
|
|
220
|
+
Update a record with a variable data object. Preferred for dynamic updates.
|
|
221
|
+
|
|
222
|
+
```xs
|
|
223
|
+
var $updates { value = { updated_at: now } }
|
|
224
|
+
|
|
225
|
+
conditional {
|
|
226
|
+
if ($input.name != null) {
|
|
227
|
+
var.update $updates { value = $updates|set:"name":$input.name }
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
conditional {
|
|
231
|
+
if ($input.price != null) {
|
|
232
|
+
var.update $updates { value = $updates|set:"price":$input.price }
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
db.patch "product" {
|
|
237
|
+
field_name = "id"
|
|
238
|
+
field_value = $input.product_id
|
|
239
|
+
data = $updates
|
|
240
|
+
} as $product
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## db.add_or_edit
|
|
246
|
+
|
|
247
|
+
Upsert: insert if not exists, update if exists.
|
|
248
|
+
|
|
249
|
+
```xs
|
|
250
|
+
db.add_or_edit "setting" {
|
|
251
|
+
field_name = "key"
|
|
252
|
+
field_value = $input.key
|
|
253
|
+
data = {
|
|
254
|
+
key: $input.key,
|
|
255
|
+
value: $input.value,
|
|
256
|
+
updated_at: now
|
|
257
|
+
}
|
|
258
|
+
} as $setting
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## db.del
|
|
264
|
+
|
|
265
|
+
Delete a record.
|
|
266
|
+
|
|
267
|
+
```xs
|
|
268
|
+
db.del "product" {
|
|
269
|
+
field_name = "id"
|
|
270
|
+
field_value = $input.product_id
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## db.truncate
|
|
277
|
+
|
|
278
|
+
Delete all records from a table.
|
|
279
|
+
|
|
280
|
+
```xs
|
|
281
|
+
db.truncate "temp_data" {
|
|
282
|
+
reset = true # Reset auto-increment
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## db.direct_query
|
|
289
|
+
|
|
290
|
+
Execute raw SQL (use sparingly).
|
|
291
|
+
|
|
292
|
+
```xs
|
|
293
|
+
db.direct_query {
|
|
294
|
+
sql = "SELECT * FROM users WHERE email = ? AND status = ?"
|
|
295
|
+
arg = [$input.email, "active"]
|
|
296
|
+
response_type = "list" # list or single
|
|
297
|
+
} as $results
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## db.transaction
|
|
303
|
+
|
|
304
|
+
Execute operations atomically.
|
|
305
|
+
|
|
306
|
+
```xs
|
|
307
|
+
db.transaction {
|
|
308
|
+
stack {
|
|
309
|
+
db.add "order" {
|
|
310
|
+
data = { user_id: $auth.id, total: $total }
|
|
311
|
+
} as $order
|
|
312
|
+
|
|
313
|
+
foreach ($input.items) {
|
|
314
|
+
each as $item {
|
|
315
|
+
db.add "order_item" {
|
|
316
|
+
data = {
|
|
317
|
+
order_id: $order.id,
|
|
318
|
+
product_id: $item.product_id,
|
|
319
|
+
quantity: $item.quantity
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
db.edit "user" {
|
|
326
|
+
field_name = "id"
|
|
327
|
+
field_value = $auth.id
|
|
328
|
+
data = { last_order_at: now }
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Query Filters
|
|
337
|
+
|
|
338
|
+
Filters for use in `where` clauses:
|
|
339
|
+
|
|
340
|
+
### String/Text
|
|
341
|
+
```xs
|
|
342
|
+
$db.name|to_lower # Case conversion
|
|
343
|
+
$db.name|concat:" " # Concatenation
|
|
344
|
+
$db.text|substr:0:100 # Substring
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Numeric
|
|
348
|
+
```xs
|
|
349
|
+
$db.price|round:2
|
|
350
|
+
$db.price|floor
|
|
351
|
+
$db.price|ceil
|
|
352
|
+
$db.price|add:10
|
|
353
|
+
$db.price|mul:1.1
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Timestamp
|
|
357
|
+
```xs
|
|
358
|
+
$db.created_at|timestamp_year
|
|
359
|
+
$db.created_at|timestamp_month
|
|
360
|
+
$db.created_at|timestamp_add_days:7
|
|
361
|
+
$db.created_at|timestamp_subtract_hours:24
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Geographic
|
|
365
|
+
```xs
|
|
366
|
+
$db.location|distance:$input.point # Distance in meters
|
|
367
|
+
$db.location|within:$input.point:1000 # Within radius
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Vector (AI/ML)
|
|
371
|
+
```xs
|
|
372
|
+
$db.embedding|cosine_similarity:$input.vector
|
|
373
|
+
$db.embedding|l2_distance_euclidean:$input.vector
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Full-Text Search
|
|
377
|
+
```xs
|
|
378
|
+
$db.content|search_rank:$input.query
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## External Databases
|
|
384
|
+
|
|
385
|
+
Connect to external databases:
|
|
386
|
+
|
|
387
|
+
```xs
|
|
388
|
+
# PostgreSQL
|
|
389
|
+
db.external.postgres.direct_query {
|
|
390
|
+
connection_string = $env.EXTERNAL_PG_URL
|
|
391
|
+
sql = "SELECT * FROM users WHERE id = ?"
|
|
392
|
+
arg = [$input.user_id]
|
|
393
|
+
response_type = "single"
|
|
394
|
+
} as $user
|
|
395
|
+
|
|
396
|
+
# MySQL
|
|
397
|
+
db.external.mysql.direct_query { ... }
|
|
398
|
+
|
|
399
|
+
# MS SQL
|
|
400
|
+
db.external.mssql.direct_query { ... }
|
|
401
|
+
|
|
402
|
+
# Oracle
|
|
403
|
+
db.external.oracle.direct_query { ... }
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Best Practices
|
|
409
|
+
|
|
410
|
+
1. **Use db.query for searches** - Flexible filtering and pagination
|
|
411
|
+
2. **Use db.get for single lookups** - Simpler than db.query with single return
|
|
412
|
+
3. **Use db.patch for dynamic updates** - Accepts variable data
|
|
413
|
+
4. **Use transactions for atomicity** - Ensure all-or-nothing operations
|
|
414
|
+
5. **Add indexes** - Index fields used in where clauses
|
|
415
|
+
6. **Use null-safe operators** - `==?` for optional filters
|
|
416
|
+
7. **Paginate results** - Never return unbounded lists
|
|
417
|
+
8. **Validate before delete** - Check ownership/permissions
|