@xano/developer-mcp 1.0.0

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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +261 -0
  3. package/api_docs/addon.md +193 -0
  4. package/api_docs/agent.md +154 -0
  5. package/api_docs/api_group.md +236 -0
  6. package/api_docs/authentication.md +68 -0
  7. package/api_docs/file.md +190 -0
  8. package/api_docs/function.md +217 -0
  9. package/api_docs/history.md +263 -0
  10. package/api_docs/index.md +104 -0
  11. package/api_docs/mcp_server.md +139 -0
  12. package/api_docs/middleware.md +205 -0
  13. package/api_docs/realtime.md +153 -0
  14. package/api_docs/table.md +151 -0
  15. package/api_docs/task.md +191 -0
  16. package/api_docs/tool.md +216 -0
  17. package/api_docs/triggers.md +344 -0
  18. package/api_docs/workspace.md +246 -0
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.js +495 -0
  21. package/package.json +49 -0
  22. package/xanoscript_docs/README.md +1 -0
  23. package/xanoscript_docs/api_query_examples.md +1255 -0
  24. package/xanoscript_docs/api_query_guideline.md +129 -0
  25. package/xanoscript_docs/build_from_lovable.md +715 -0
  26. package/xanoscript_docs/db_query_guideline.md +427 -0
  27. package/xanoscript_docs/ephemeral_environment_guideline.md +529 -0
  28. package/xanoscript_docs/expression_guideline.md +1086 -0
  29. package/xanoscript_docs/frontend_guideline.md +67 -0
  30. package/xanoscript_docs/function_examples.md +1406 -0
  31. package/xanoscript_docs/function_guideline.md +130 -0
  32. package/xanoscript_docs/functions.md +2155 -0
  33. package/xanoscript_docs/input_guideline.md +227 -0
  34. package/xanoscript_docs/mcp_server_examples.md +36 -0
  35. package/xanoscript_docs/mcp_server_guideline.md +69 -0
  36. package/xanoscript_docs/query_filter.md +489 -0
  37. package/xanoscript_docs/table_examples.md +586 -0
  38. package/xanoscript_docs/table_guideline.md +137 -0
  39. package/xanoscript_docs/task_examples.md +511 -0
  40. package/xanoscript_docs/task_guideline.md +103 -0
  41. package/xanoscript_docs/tips_and_tricks.md +144 -0
  42. package/xanoscript_docs/tool_examples.md +69 -0
  43. package/xanoscript_docs/tool_guideline.md +139 -0
  44. package/xanoscript_docs/unit_testing_guideline.md +328 -0
  45. package/xanoscript_docs/version.json +3 -0
  46. package/xanoscript_docs/workspace.md +17 -0
@@ -0,0 +1,427 @@
1
+ # Xano Database Query Guidelines
2
+
3
+ ## db.query
4
+
5
+ The `db.query` is the most used and the most flexible database query, it is used to retrieve data from your database (not unlike a SQL `SELECT` statement). It allows you to specify the table, filters, sorting, and pagination options.
6
+
7
+ ### Search Argument
8
+
9
+ The `search` is the equivalent of a SQL `WHERE` clause. It allows you to filter records based on specific conditions. The list of available operators includes:
10
+
11
+ #### Basic Comparison Operators
12
+
13
+ Basic comparison operators are:
14
+
15
+ - `==` (equals)
16
+ - `!=` (not equals)
17
+ - `>` (greater than)
18
+ - `>=` (greater than or equal)
19
+ - `<` (less than)
20
+ - `<=` (less than or equal)
21
+
22
+ **Examples**
23
+ Tests if two values are equal.
24
+
25
+ ```xs
26
+ db.query "post" {
27
+ where = $db.post.user_id == $auth.id
28
+ } as $posts
29
+ ```
30
+
31
+ Tests if two values are not equal.
32
+
33
+ ```xs
34
+ db.query "post" {
35
+ where = $db.post.status != "draft"
36
+ } as $published_posts
37
+ ```
38
+
39
+ #### Array Content Operators
40
+
41
+ **`contains` (contains) and `not contains` (does not contain)**
42
+ Tests if an array contains a specific value.
43
+
44
+ IMPORTANT, DO NOT USE `icontains` IT IS NOT VALID IN A QUERY
45
+ use `contains` instead as it is case insensitive by default.
46
+
47
+ Tests if a field does not contain a specific value.
48
+
49
+ ```xs
50
+ db.query "post" {
51
+ description = "Posts without specific tags"
52
+ where = $db.post.tags not contains "deprecated"
53
+ } as $current_posts
54
+ ```
55
+
56
+ #### String Content Operators
57
+
58
+ **`includes` (includes)**
59
+ Tests if a string includes a particular phrase / value.
60
+
61
+ ```xs
62
+ db.query "post" {
63
+ description = "Posts with specific title content"
64
+ where = $db.post.title includes "tutorial"
65
+ } as $tutorial_posts
66
+ ```
67
+
68
+ #### Array Overlap Operators
69
+
70
+ **`overlaps` (overlaps) and `not overlaps` (does not overlap)**
71
+ Tests if two arrays have any elements in common. Useful for comparing array fields.
72
+
73
+ ```xs
74
+ db.query "post" {
75
+ description = "Posts with overlapping tags"
76
+ where = $db.post.tags overlaps ["javascript", "react"]
77
+ } as $matching_posts
78
+ ```
79
+
80
+ Tests if two arrays have no elements in common.
81
+
82
+ ```xs
83
+ db.query "post" {
84
+ description = "Posts without conflicting tags"
85
+ where = $db.post.tags not overlaps ["outdated", "deprecated"]
86
+ } as $valid_posts
87
+ ```
88
+
89
+ #### Combining Conditions
90
+
91
+ You can combine multiple conditions using logical operators:
92
+
93
+ **`&&` (logical AND)**
94
+
95
+ ```xs
96
+ db.query "post" {
97
+ where = $db.post.user_id == $auth.id && $db.post.status == "published"
98
+ } as $my_published_posts
99
+ ```
100
+
101
+ **`||` (logical OR)**
102
+
103
+ ```xs
104
+ db.query "post" {
105
+ where = $db.post.user_id == $auth.id || $db.post.status == "published"
106
+ } as $my_published_posts
107
+ ```
108
+
109
+ #### Ignore if null Operators
110
+
111
+ When filtering data, some condition might be optional based on user input. In such cases, you can use the `?` operator after the comparison operator (`==` would become `==?`) to ignore that condition if the value is null. For example, if you have an optional `category` input parameter, you can write:
112
+
113
+ ```xs
114
+ db.query "post" {
115
+ where = $db.post.category ==? $input.category
116
+ } as $filtered_posts
117
+ ```
118
+
119
+ If you have a set of advanced search filters, you can use multiple ignore-if-null conditions:
120
+
121
+ ```xs
122
+ db.query "post" {
123
+ where = $db.post.category ==? $input.category && $db.post.status ==? $input.status && $db.post.created_at >=? $input.start_date && $db.post.created_at <=? $input.end_date
124
+ } as $filtered_posts
125
+ ```
126
+
127
+ This way, if any of the input parameters are null, that specific condition will be ignored in the query.
128
+
129
+ ### join
130
+
131
+ binding allows you to join related tables in your query. You can specify the relationship using the `bind` argument, which takes an array of objects defining the join conditions.
132
+
133
+ ```xs
134
+ db.query "comment" {
135
+ where = $db.post.user_id == $auth.id && $db.post.status == "published" && $db.post.created_at > ("now"|timestamp_add_days:-30)
136
+ join = {
137
+ post: {
138
+ table : "post"
139
+ type : "inner"
140
+ where: $db.comment.post_id == $db.post.id
141
+ }
142
+ }
143
+ } as $my_published_posts
144
+ ```
145
+
146
+ The joins can be of type `inner`, `left`, or `right`, depending on your needs.
147
+
148
+ Note that joining a table does not return its fields; it only allows you to use those fields in the `search` condition. If you wanted to return fields from the joined table, you would want to either use an `eval` to map some of the values retrieved from the join or use an `addon` which would fetch the related data separately.
149
+
150
+ ### Addon
151
+
152
+ An Addon is a function that is running a single `db.query` statement to fetch related data for each record returned by the main query. This is useful for fetching related records without using joins. Note that only a single `db.query` statement is allowed in an addon stack, no other operations is allowed.
153
+
154
+ For example, if you wanted to fetch blog posts along with their likes and comments, you could use addons like this (assuming you have `blog_post_likes` and `blog_post_comments` addons defined):
155
+
156
+ ```xs
157
+ db.query blog_post {
158
+ where = $db.blog_post.author_id == $auth.id
159
+ sort = {blog_post.publication_date: "desc"}
160
+ return = {type: "list", paging: {page: 1, per_page: 25, totals: true}}
161
+ addon = [
162
+ {
163
+ name : "blog_post_like_count"
164
+ input: {blog_post_id: $output.id}
165
+ as : "items.like_count"
166
+ }
167
+ {
168
+ name : "blog_post_comment_count"
169
+ input: {blog_post_id: $output.id}
170
+ as : "items.comment_count"
171
+ }
172
+ ]
173
+ } as $posts
174
+ ```
175
+
176
+ The `blog_post_like_count` addon could be defined as:
177
+
178
+ ```xs
179
+ addon blog_post_like_count {
180
+ input {
181
+ uuid blog_post_id? {
182
+ table = "blog_post"
183
+ }
184
+ }
185
+
186
+ stack {
187
+ db.query blog_post_like {
188
+ where = $db.blog_post_like.blog_post_id == $input.blog_post_id
189
+ return = {type: "count"}
190
+ }
191
+ }
192
+ }
193
+ ```
194
+
195
+ and the `blog_post_comment_count` addon could be defined as:
196
+
197
+ ```xs
198
+ addon blog_post_comment_count {
199
+ input {
200
+ uuid blog_post_id? {
201
+ table = "blog_post"
202
+ }
203
+ }
204
+
205
+ stack {
206
+ db.query blog_post_comment {
207
+ where = $db.blog_post_comment.blog_post_id == $input.blog_post_id
208
+ return = {type: "count"}
209
+ }
210
+ }
211
+ }
212
+ ```
213
+
214
+ ### Eval
215
+
216
+ Eval allows you to create computed fields based on existing fields in your database (or joined tables). You can define these computed fields using the `eval` argument, which takes an array of objects specifying the computation.
217
+
218
+ ```xs
219
+ db.query "blog_post" {
220
+ join = {
221
+ user: {table: "user", where: $db.post.user_id == $db.user.id}
222
+ }
223
+
224
+ where = $db.post.user_id == $auth.id
225
+ eval = {status: $db.user.status, userName: $db.user.name}
226
+ return = {type: "list"}
227
+ } as $posts
228
+ ```
229
+
230
+ ### Return types
231
+
232
+ - `count`: Returns the number of matching records.
233
+ - `exists`: Returns whether any matching records exist.
234
+ - `single`: Returns a single matching record.
235
+ - `list`: Returns a list of matching records.
236
+
237
+ #### Return List
238
+
239
+ This is the default format when none is specified. You can specify pagination, sorting, and whether to include metadata.
240
+
241
+ You can specify sorting :
242
+
243
+ ```xs
244
+ db.query "blog_post_comment" {
245
+ where = $db.blog_post_comment.user_id == $auth.id && $db.blog_post_comment.status == "published"
246
+ sort = {post.created_at: "asc"}
247
+ return = {type: "list"}
248
+ } as $my_published_posts
249
+ ```
250
+
251
+ sorting can be `asc`, `desc` or `rand` (random order).
252
+
253
+ You can also specify pagination (and combine it with sorting):
254
+
255
+ ```xs
256
+ db.query "blog_post_comment" {
257
+ join = {
258
+ post: {
259
+ table : "blog_post"
260
+ where: $db.blog_post_comment.post_id == $db.blog_post.id
261
+ }
262
+ }
263
+
264
+ where = $db.blog_post_comment.user_id == $auth.id
265
+ additional_where = $input.query
266
+ sort = { blog_post.created_at: "asc" }
267
+ return = { type: "list", paging: { page: $input.page, per_page: 25 } }
268
+ } as $my_published_posts
269
+ ```
270
+
271
+ paging defines the default constant you want to use for pagination, while external_simple allows you to override those values (here $input parameters).
272
+
273
+ This pagination will move the results into a new structure as:
274
+
275
+ ```json
276
+ {
277
+ "itemsReceived": integer,
278
+ "curPage": integer,
279
+ "nextPage": integer,
280
+ "prevPage": integer,
281
+ "offset": integer,
282
+ "perPage": integer,
283
+ "items": [ ... ]
284
+ }
285
+ ```
286
+
287
+ #### Return Single
288
+
289
+ Returns a single matching record. If multiple records match, only the first one is returned.
290
+
291
+ ```xs
292
+ db.query "comment" {
293
+ where = $db.comment.user_id == $auth.id
294
+ return = {
295
+ type: "single"
296
+ }
297
+ } as $my_published_posts
298
+ ```
299
+
300
+ #### Return Count
301
+
302
+ Returns the number of matching records as an integer.
303
+
304
+ ```xs
305
+ db.query "comment" {
306
+ where = $db.comment.user_id == $auth.id
307
+ return = {
308
+ type: "count"
309
+ }
310
+ } as $post_count
311
+ ```
312
+
313
+ #### Return Exists
314
+
315
+ Returns whether any matching records exist as a boolean.
316
+
317
+ ```xs
318
+ db.query "comment" {
319
+ where = $db.comment.user_id == $auth.id
320
+ return = {
321
+ type: "exists"
322
+ }
323
+ } as $has_posts
324
+ ```
325
+
326
+ ### Other convenience query operations
327
+
328
+ #### db.get
329
+
330
+ Retrieving a single record by its primary key can be done using `db.get`:
331
+
332
+ ```xs
333
+ db.get "follow" {
334
+ field_name = "id"
335
+ field_value = $input.follow_id
336
+ } as $follow_record
337
+ ```
338
+
339
+ #### db.has
340
+
341
+ Checking for the existence of a record can be done using `db.has`:
342
+
343
+ ```xs
344
+ db.has "category" {
345
+ field_name = "id"
346
+ field_value = $input.query
347
+ } as $category_exists
348
+ ```
349
+
350
+ #### Modifying your table
351
+
352
+ Adding a new record can be done using `db.add`:
353
+
354
+ ```xs
355
+ db.add "post" {
356
+ data = {
357
+ user_id : $auth.id
358
+ caption : $input.caption
359
+ image_url: $input.image_url
360
+ status : "draft"
361
+ }
362
+ } as $new_post
363
+ ```
364
+
365
+ Editing a record can be done using `db.patch` this is preferred method to update a record and when the payload is built dynamically since the data object also accepts a variable.
366
+
367
+ ```xs
368
+ var $payload {
369
+ value = {status: "active"}
370
+ }
371
+
372
+ conditional {
373
+ if ($input.is_featured) {
374
+ var.update $payload.featured {
375
+ value = true
376
+ }
377
+ }
378
+
379
+ else {
380
+ var.update $payload.featured {
381
+ value = false
382
+ }
383
+ }
384
+ }
385
+
386
+ db.patch cards {
387
+ field_name = "id"
388
+ field_value = $input.card_id
389
+ data = $payload
390
+ } as $cards1
391
+ ```
392
+
393
+ Editing a record can also be done using `db.edit`. This method does not accept a variable for the data object and requires the fields to be updated to be specified in place.
394
+
395
+ ```xs
396
+ db.edit "post" {
397
+ field_name = "id"
398
+ field_value = $input.post_id
399
+ data = {
400
+ caption : input.value
401
+ image_url: $input.image_url || $post.image_url
402
+ }
403
+ } as $edited_post
404
+ ```
405
+
406
+ Adding or editing (upsert) a record can be done using `db.add_or_edit`. In this case, if the `field_value` is empty, a new record will be created; otherwise, the existing record will be updated.
407
+
408
+ ```xs
409
+ db.add_or_edit "category" {
410
+ field_name = "name"
411
+ field_value = "$input.category"
412
+ data = {
413
+ name: $input.name
414
+ }
415
+ } as $category_record
416
+ ```
417
+
418
+ #### db.del
419
+
420
+ Deleting a record can be done using `db.del` (notice how delete does not return the deleted record):
421
+
422
+ ```xs
423
+ db.del "post" {
424
+ field_name = "id"
425
+ field_value = $input.post_id
426
+ }
427
+ ```