Skip to main content

wowlab_sentinel/mcp/tools/query/
types.rs

1use 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}