wowlab_sentinel/mcp/tools/query/
types.rs1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5const DEFAULT_QUERY_LIMIT: u64 = 100;
6
7#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
8#[schemars(
9 description = "Single table query. Run `get_schema` first to see valid tables and columns."
10)]
11pub(crate) struct TableQuery {
12 #[schemars(description = "Table name from `get_schema` (e.g. `game.spells`, `game.items`)")]
13 pub table: String,
14 #[serde(default)]
15 #[schemars(description = "Filter conditions, AND-ed together. Omit for unfiltered results.")]
16 pub filters: Vec<Filter>,
17 #[serde(default)]
18 #[schemars(description = "Column to sort by. Must exist in the table.")]
19 pub order_by: Option<String>,
20 #[serde(default)]
21 #[schemars(description = "Sort descending. Default: false (ascending).")]
22 pub order_desc: bool,
23 #[serde(default = "default_limit")]
24 #[schemars(description = "Max rows to return. Default: 100, max: 1000.")]
25 pub limit: u64,
26 #[serde(default)]
27 #[schemars(description = "Rows to skip (for pagination).")]
28 pub offset: Option<u64>,
29}
30
31const fn default_limit() -> u64 {
32 DEFAULT_QUERY_LIMIT
33}
34
35#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
36#[schemars(description = "Batch of queries. Each uses the same schema as `query`.")]
37pub(crate) struct TableBatchQuery {
38 #[schemars(description = "Array of TableQuery objects (max 50). Each runs independently.")]
39 pub queries: Vec<TableQuery>,
40}
41
42#[derive(Clone, Debug, JsonSchema, Serialize)]
43#[schemars(description = "Result for a single query in a batch request")]
44pub(super) struct BatchQueryResult {
45 #[schemars(description = "Zero-based index of this query in the batch input")]
46 pub index: usize,
47 #[schemars(description = "Table that was queried")]
48 pub table: String,
49 #[schemars(description = "Number of rows returned for this query")]
50 pub row_count: usize,
51 #[schemars(description = "Rows returned for this query. Null when this query failed.")]
52 pub results: Option<Vec<Value>>,
53 #[schemars(description = "Query error message when this query failed, otherwise null")]
54 pub error: Option<String>,
55}
56
57#[derive(Clone, Debug, Deserialize, JsonSchema)]
58#[schemars(description = "A single filter condition to apply to the query")]
59pub(crate) struct Filter {
60 #[schemars(description = "Column name to filter on (must exist in the table)")]
61 pub column: String,
62 #[schemars(description = "Comparison operation to apply")]
63 pub op: FilterOp,
64 #[serde(default)]
65 #[schemars(
66 description = "Value to compare against (type must match column: int, text, bool, or json for jsonb ops)"
67 )]
68 pub value: Option<Value>,
69}
70
71#[derive(Clone, Debug, Deserialize, JsonSchema)]
72#[serde(rename_all = "snake_case")]
73#[schemars(description = "Filter comparison operation")]
74#[non_exhaustive]
75pub(crate) enum FilterOp {
76 #[schemars(description = "Equals (works with int, text, bool)")]
77 Eq,
78 #[schemars(description = "Not equals (works with int, text, bool)")]
79 Ne,
80 #[schemars(description = "Greater than (works with int)")]
81 Gt,
82 #[schemars(description = "Greater than or equal (works with int)")]
83 Gte,
84 #[schemars(description = "Less than (works with int)")]
85 Lt,
86 #[schemars(description = "Less than or equal (works with int)")]
87 Lte,
88 #[schemars(description = "Text contains substring (works with text columns only)")]
89 Contains,
90 #[schemars(description = "Text starts with prefix (works with text columns only)")]
91 StartsWith,
92 #[schemars(description = "Match any value in a list (works with int, float, text, bool)")]
93 In,
94 #[schemars(
95 description = "JSONB contains (json columns only). Value is matched with @> operator. Example: {\"effect\": 68}"
96 )]
97 JsonbContains,
98 #[schemars(description = "JSONB has key (json columns only). Value is a string key name.")]
99 JsonbHasKey,
100 #[schemars(
101 description = "JSONB array contains element (json columns only). Value is an object to match within the array. Wraps value in [] automatically."
102 )]
103 JsonbArrayContains,
104 #[schemars(
105 description = "Integer array contains element (int_array columns only). Value is a single integer. Matches rows where the column array contains the value."
106 )]
107 ArrayContains,
108}
109
110#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
111#[schemars(
112 description = "Count rows matching filters. Same filters as `query` but returns only the count."
113)]
114pub(crate) struct CountQuery {
115 #[schemars(description = "Table name from `get_schema` (e.g. `game.spells`, `game.items`)")]
116 pub table: String,
117 #[serde(default)]
118 #[schemars(description = "Filter conditions, AND-ed together. Omit to count all rows.")]
119 pub filters: Vec<Filter>,
120}
121
122#[derive(Debug, Serialize)]
123pub(super) struct CountResult {
124 pub table: String,
125 pub count: i64,
126}