@xano/developer-mcp 1.0.7 → 1.0.9

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.
@@ -405,6 +405,164 @@ db.external.oracle.direct_query { ... }
405
405
 
406
406
  ---
407
407
 
408
+ ## Bulk Operations
409
+
410
+ Perform batch operations on multiple records efficiently.
411
+
412
+ ### db.bulk.add
413
+
414
+ Insert multiple records in a single operation.
415
+
416
+ ```xs
417
+ db.bulk.add "product" {
418
+ data = [
419
+ { name: "Product A", price: 10.00, sku: "SKU-A" },
420
+ { name: "Product B", price: 20.00, sku: "SKU-B" },
421
+ { name: "Product C", price: 30.00, sku: "SKU-C" }
422
+ ]
423
+ } as $inserted
424
+ ```
425
+
426
+ ### db.bulk.update
427
+
428
+ Update multiple records matching conditions.
429
+
430
+ ```xs
431
+ db.bulk.update "product" {
432
+ where = $db.product.category_id == $input.category_id
433
+ data = {
434
+ is_featured: true,
435
+ updated_at: now
436
+ }
437
+ } as $count
438
+ ```
439
+
440
+ ### db.bulk.patch
441
+
442
+ Patch multiple records with variable data.
443
+
444
+ ```xs
445
+ var $updates { value = { updated_at: now } }
446
+
447
+ conditional {
448
+ if ($input.discount != null) {
449
+ var.update $updates { value = $updates|set:"discount":$input.discount }
450
+ }
451
+ }
452
+
453
+ db.bulk.patch "product" {
454
+ where = $db.product.category_id == $input.category_id
455
+ data = $updates
456
+ } as $count
457
+ ```
458
+
459
+ ### db.bulk.delete
460
+
461
+ Delete multiple records matching conditions.
462
+
463
+ ```xs
464
+ db.bulk.delete "temp_session" {
465
+ where = $db.temp_session.expires_at < now
466
+ } as $deleted_count
467
+ ```
468
+
469
+ ### Bulk with Transaction
470
+
471
+ ```xs
472
+ db.transaction {
473
+ stack {
474
+ db.bulk.delete "order_item" {
475
+ where = $db.order_item.order_id == $input.order_id
476
+ }
477
+
478
+ db.bulk.add "order_item" {
479
+ data = $input.items|map:{
480
+ order_id: $input.order_id,
481
+ product_id: $$.product_id,
482
+ quantity: $$.quantity
483
+ }
484
+ }
485
+ }
486
+ }
487
+ ```
488
+
489
+ ---
490
+
491
+ ## Advanced Features
492
+
493
+ ### db.set_datasource
494
+
495
+ Switch to a different data source within a function.
496
+
497
+ ```xs
498
+ db.set_datasource {
499
+ name = "analytics_db"
500
+ }
501
+
502
+ db.query "metrics" {
503
+ where = $db.metrics.date >= $input.start_date
504
+ } as $metrics
505
+
506
+ db.set_datasource {
507
+ name = "default"
508
+ }
509
+ ```
510
+
511
+ ### db.schema
512
+
513
+ Get schema information for a table.
514
+
515
+ ```xs
516
+ db.schema {
517
+ table = "user"
518
+ } as $schema
519
+
520
+ // $schema contains:
521
+ // - columns: array of column definitions
522
+ // - indexes: array of index definitions
523
+ // - constraints: array of constraints
524
+ ```
525
+
526
+ ### Transaction Isolation Levels
527
+
528
+ ```xs
529
+ db.transaction {
530
+ isolation = "serializable" // serializable, repeatable_read, read_committed
531
+ stack {
532
+ // Operations run with specified isolation
533
+ }
534
+ }
535
+ ```
536
+
537
+ ### Deadlock Handling
538
+
539
+ ```xs
540
+ try_catch {
541
+ try {
542
+ db.transaction {
543
+ stack {
544
+ db.edit "inventory" { ... }
545
+ db.edit "order" { ... }
546
+ }
547
+ }
548
+ }
549
+ catch {
550
+ conditional {
551
+ if ($error.name == "DeadlockError") {
552
+ // Retry logic
553
+ util.sleep { value = 100 }
554
+ function.run "retry_transaction" { input = $input }
555
+ }
556
+ else {
557
+ throw { name = $error.name, value = $error.message }
558
+ }
559
+ }
560
+ }
561
+ }
562
+ ```
563
+
564
+ ---
565
+
408
566
  ## Best Practices
409
567
 
410
568
  1. **Use db.query for searches** - Flexible filtering and pagination
@@ -412,3 +570,5 @@ db.external.oracle.direct_query { ... }
412
570
  3. **Use db.patch for dynamic updates** - Accepts variable data
413
571
  4. **Use transactions for atomicity** - Ensure all-or-nothing operations
414
572
  5. **Use null-safe operators** - `==?` for optional filters
573
+ 6. **Use bulk operations for batch processing** - More efficient than loops
574
+ 7. **Handle deadlocks gracefully** - Implement retry logic for concurrent writes
@@ -0,0 +1,342 @@
1
+ ---
2
+ applyTo: "**/*.xs"
3
+ ---
4
+
5
+ # Debugging
6
+
7
+ Tools for logging, inspecting, and debugging XanoScript execution.
8
+
9
+ ## Quick Reference
10
+
11
+ | Operation | Purpose |
12
+ |-----------|---------|
13
+ | `debug.log` | Log message to console |
14
+ | `debug.stop` | Stop execution at point |
15
+ | Request history | View past executions |
16
+
17
+ ---
18
+
19
+ ## debug.log
20
+
21
+ Log messages and values for debugging.
22
+
23
+ ```xs
24
+ debug.log { value = "Starting process" }
25
+
26
+ debug.log { value = $user }
27
+
28
+ debug.log { value = { step: "validation", data: $input } }
29
+ ```
30
+
31
+ ### With Labels
32
+
33
+ ```xs
34
+ debug.log {
35
+ label = "User Data"
36
+ value = $user
37
+ }
38
+
39
+ debug.log {
40
+ label = "Query Result"
41
+ value = $products
42
+ }
43
+ ```
44
+
45
+ ### Conditional Logging
46
+
47
+ ```xs
48
+ conditional {
49
+ if ($env.DEBUG == "true") {
50
+ debug.log {
51
+ label = "Debug Info"
52
+ value = {
53
+ input: $input,
54
+ auth: $auth,
55
+ timestamp: now
56
+ }
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ ---
63
+
64
+ ## debug.stop
65
+
66
+ Halt execution at a specific point for inspection.
67
+
68
+ ```xs
69
+ debug.log { value = "Before database call" }
70
+
71
+ db.query "user" {
72
+ where = $db.user.id == $input.user_id
73
+ } as $user
74
+
75
+ debug.stop // Execution pauses here
76
+
77
+ // Code below does not run
78
+ db.edit "user" { ... }
79
+ ```
80
+
81
+ ### Conditional Stop
82
+
83
+ ```xs
84
+ conditional {
85
+ if ($user == null) {
86
+ debug.log { value = "User not found, stopping" }
87
+ debug.stop
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### With Data Inspection
93
+
94
+ ```xs
95
+ debug.log {
96
+ label = "State at stop point"
97
+ value = {
98
+ input: $input,
99
+ user: $user,
100
+ calculated: $total
101
+ }
102
+ }
103
+ debug.stop
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Logging Patterns
109
+
110
+ ### Request Tracing
111
+
112
+ ```xs
113
+ function "process_order" {
114
+ input { int order_id }
115
+ stack {
116
+ var $trace_id { value = |uuid }
117
+
118
+ debug.log {
119
+ label = "TRACE_START"
120
+ value = { trace_id: $trace_id, order_id: $input.order_id }
121
+ }
122
+
123
+ // ... processing ...
124
+
125
+ debug.log {
126
+ label = "TRACE_END"
127
+ value = { trace_id: $trace_id, status: "success" }
128
+ }
129
+ }
130
+ }
131
+ ```
132
+
133
+ ### Error Context
134
+
135
+ ```xs
136
+ try_catch {
137
+ try {
138
+ function.run "risky_operation" { input = $data }
139
+ }
140
+ catch {
141
+ debug.log {
142
+ label = "ERROR"
143
+ value = {
144
+ operation: "risky_operation",
145
+ input: $data,
146
+ error: $error.message,
147
+ stack: $error.stack
148
+ }
149
+ }
150
+ throw { name = $error.name, value = $error.message }
151
+ }
152
+ }
153
+ ```
154
+
155
+ ### Performance Timing
156
+
157
+ ```xs
158
+ var $start { value = now|to_ms }
159
+
160
+ db.query "product" { ... } as $products
161
+
162
+ var $query_time { value = (now|to_ms) - $start }
163
+
164
+ debug.log {
165
+ label = "PERF"
166
+ value = {
167
+ operation: "product_query",
168
+ duration_ms: $query_time,
169
+ record_count: $products|count
170
+ }
171
+ }
172
+ ```
173
+
174
+ ### Step-by-Step
175
+
176
+ ```xs
177
+ debug.log { value = "Step 1: Validating input" }
178
+ // validation code
179
+
180
+ debug.log { value = "Step 2: Fetching user" }
181
+ db.get "user" { ... } as $user
182
+
183
+ debug.log { value = "Step 3: Processing order" }
184
+ // order processing
185
+
186
+ debug.log { value = "Step 4: Sending notification" }
187
+ // notification code
188
+
189
+ debug.log { value = "Complete" }
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Inspecting Variables
195
+
196
+ ### Object Inspection
197
+
198
+ ```xs
199
+ debug.log {
200
+ label = "User object"
201
+ value = $user
202
+ }
203
+
204
+ // Logs full object structure:
205
+ // {
206
+ // id: 123,
207
+ // name: "John",
208
+ // email: "john@example.com",
209
+ // ...
210
+ // }
211
+ ```
212
+
213
+ ### Array Inspection
214
+
215
+ ```xs
216
+ debug.log {
217
+ label = "Products"
218
+ value = {
219
+ count: $products|count,
220
+ first: $products|first,
221
+ last: $products|last,
222
+ sample: $products|slice:0:3
223
+ }
224
+ }
225
+ ```
226
+
227
+ ### Expression Evaluation
228
+
229
+ ```xs
230
+ debug.log {
231
+ label = "Calculated values"
232
+ value = {
233
+ total: $items|map:$$.price * $$.quantity|sum,
234
+ tax: ($items|map:$$.price * $$.quantity|sum) * 0.08,
235
+ item_count: $items|count
236
+ }
237
+ }
238
+ ```
239
+
240
+ ---
241
+
242
+ ## Environment-Based Debugging
243
+
244
+ ### Development Only
245
+
246
+ ```xs
247
+ conditional {
248
+ if ($env.ENVIRONMENT == "development") {
249
+ debug.log { value = "Development mode: verbose logging enabled" }
250
+ debug.log { value = $input }
251
+ }
252
+ }
253
+ ```
254
+
255
+ ### Debug Flag
256
+
257
+ ```xs
258
+ // Enable with environment variable DEBUG=true
259
+ conditional {
260
+ if ($env.DEBUG|to_bool == true) {
261
+ debug.log {
262
+ label = "Debug"
263
+ value = { step: "after_query", data: $result }
264
+ }
265
+ }
266
+ }
267
+ ```
268
+
269
+ ---
270
+
271
+ ## Request History
272
+
273
+ View past request executions in the Xano dashboard:
274
+
275
+ 1. Navigate to API endpoint or function
276
+ 2. Click "Request History"
277
+ 3. View inputs, outputs, and debug logs
278
+ 4. Inspect step-by-step execution
279
+
280
+ ### What's Captured
281
+
282
+ - Input parameters
283
+ - Output response
284
+ - All debug.log messages
285
+ - Execution time per step
286
+ - Database queries executed
287
+ - External API calls made
288
+ - Errors and stack traces
289
+
290
+ ---
291
+
292
+ ## Debugging Strategies
293
+
294
+ ### Isolate the Problem
295
+
296
+ ```xs
297
+ // Comment out sections to isolate issues
298
+ debug.log { value = "Checkpoint 1" }
299
+ // potentially problematic code
300
+ debug.log { value = "Checkpoint 2" }
301
+ ```
302
+
303
+ ### Validate Assumptions
304
+
305
+ ```xs
306
+ debug.log {
307
+ label = "Assumption check"
308
+ value = {
309
+ user_exists: $user != null,
310
+ has_permission: $user.role == "admin",
311
+ input_valid: $input.amount > 0
312
+ }
313
+ }
314
+ ```
315
+
316
+ ### Compare Expected vs Actual
317
+
318
+ ```xs
319
+ var $expected { value = 100 }
320
+ var $actual { value = $items|count }
321
+
322
+ debug.log {
323
+ label = "Comparison"
324
+ value = {
325
+ expected: $expected,
326
+ actual: $actual,
327
+ match: $expected == $actual
328
+ }
329
+ }
330
+ ```
331
+
332
+ ---
333
+
334
+ ## Best Practices
335
+
336
+ 1. **Remove debug.stop in production** - Causes execution to halt
337
+ 2. **Use labels consistently** - Makes log searching easier
338
+ 3. **Log at boundaries** - Function entry/exit, external calls
339
+ 4. **Include context** - IDs, timestamps, relevant state
340
+ 5. **Don't log sensitive data** - Passwords, tokens, PII
341
+ 6. **Use environment flags** - Enable verbose logging conditionally
342
+ 7. **Check request history** - Built-in debugging in dashboard
@@ -292,6 +292,176 @@ function "validate_email_unique" {
292
292
 
293
293
  ---
294
294
 
295
+ ## Async Operations
296
+
297
+ ### await
298
+
299
+ Wait for an asynchronous operation to complete.
300
+
301
+ ```xs
302
+ stack {
303
+ api.request {
304
+ url = "https://api.example.com/data"
305
+ method = "GET"
306
+ async = true
307
+ } as $request
308
+
309
+ await $request as $response
310
+ }
311
+ ```
312
+
313
+ ### group (Parallel Execution)
314
+
315
+ Execute multiple operations in parallel and wait for all to complete.
316
+
317
+ ```xs
318
+ stack {
319
+ group {
320
+ api.request {
321
+ url = "https://api.example.com/users"
322
+ method = "GET"
323
+ } as $users
324
+
325
+ api.request {
326
+ url = "https://api.example.com/products"
327
+ method = "GET"
328
+ } as $products
329
+
330
+ api.request {
331
+ url = "https://api.example.com/orders"
332
+ method = "GET"
333
+ } as $orders
334
+ }
335
+
336
+ // All three requests complete before continuing
337
+ var $combined {
338
+ value = {
339
+ users: $users.body,
340
+ products: $products.body,
341
+ orders: $orders.body
342
+ }
343
+ }
344
+ }
345
+ ```
346
+
347
+ ### Parallel Database Queries
348
+
349
+ ```xs
350
+ stack {
351
+ group {
352
+ db.query "user" {
353
+ where = $db.user.is_active == true
354
+ return = { type: "count" }
355
+ } as $active_users
356
+
357
+ db.query "order" {
358
+ where = $db.order.created_at >= $input.start_date
359
+ return = { type: "count" }
360
+ } as $order_count
361
+
362
+ db.query "product" {
363
+ where = $db.product.stock == 0
364
+ return = { type: "count" }
365
+ } as $out_of_stock
366
+ }
367
+
368
+ response = {
369
+ active_users: $active_users,
370
+ orders: $order_count,
371
+ out_of_stock: $out_of_stock
372
+ }
373
+ }
374
+ ```
375
+
376
+ ---
377
+
378
+ ## Advanced Loop Patterns
379
+
380
+ ### remove (In-Loop Deletion)
381
+
382
+ Remove the current element during foreach iteration.
383
+
384
+ ```xs
385
+ stack {
386
+ var $items { value = $input.items }
387
+
388
+ foreach ($items) {
389
+ each as $item {
390
+ conditional {
391
+ if ($item.expired == true) {
392
+ remove
393
+ }
394
+ }
395
+ }
396
+ }
397
+
398
+ // $items now excludes expired items
399
+ }
400
+ ```
401
+
402
+ ### as (Variable Aliasing)
403
+
404
+ Alias loop variables for clearer access.
405
+
406
+ ```xs
407
+ foreach ($orders) {
408
+ each as $order {
409
+ // $order available here
410
+ foreach ($order.items) {
411
+ each as $item {
412
+ // Both $order and $item available
413
+ db.add "order_item" {
414
+ data = {
415
+ order_id: $order.id,
416
+ product_id: $item.product_id,
417
+ quantity: $item.quantity
418
+ }
419
+ }
420
+ }
421
+ }
422
+ }
423
+ }
424
+ ```
425
+
426
+ ### Loop Control
427
+
428
+ ```xs
429
+ foreach ($items) {
430
+ each as $item {
431
+ conditional {
432
+ if ($item.skip) {
433
+ continue // Skip to next iteration
434
+ }
435
+ }
436
+
437
+ conditional {
438
+ if ($item.stop) {
439
+ break // Exit loop entirely
440
+ }
441
+ }
442
+
443
+ // Process item
444
+ }
445
+ }
446
+ ```
447
+
448
+ ### Loop with Index
449
+
450
+ ```xs
451
+ foreach ($items) {
452
+ each as $item, $index {
453
+ db.add "item" {
454
+ data = {
455
+ value: $item,
456
+ position: $index
457
+ }
458
+ }
459
+ }
460
+ }
461
+ ```
462
+
463
+ ---
464
+
295
465
  ## Best Practices
296
466
 
297
467
  1. **Single responsibility** - Each function does one thing well
@@ -299,3 +469,5 @@ function "validate_email_unique" {
299
469
  3. **Organize in folders** - Group related functions: `utils/`, `auth/`, `orders/`
300
470
  4. **Return early** - Use return for guard clauses
301
471
  5. **Keep stacks shallow** - Avoid deeply nested conditionals
472
+ 6. **Use group for parallel calls** - Improves performance for independent operations
473
+ 7. **Use remove sparingly** - Consider filtering arrays instead