Coverage for mindsdb / integrations / handlers / discord_handler / discord_tables.py: 0%
74 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-21 00:36 +0000
1import pandas as pd
2from typing import Text, List, Dict, Any
4from mindsdb_sql_parser import ast
6from mindsdb.integrations.libs.api_handler import APITable
7from mindsdb.integrations.utilities.sql_utils import extract_comparison_conditions
9from mindsdb.integrations.libs.response import HandlerResponse as Response
11from mindsdb.integrations.utilities.handlers.query_utilities.insert_query_utilities import (
12 INSERTQueryParser
13)
15from mindsdb.utilities import log
17logger = log.getLogger(__name__)
20class MessagesTable(APITable):
21 """The Discord Table implementation"""
23 def get_columns(self):
24 return [
25 'id',
26 'type',
27 'content',
28 'author_id',
29 'author_username',
30 'author_global_name',
31 'author_avatar',
32 'author_banner_color',
33 'attachments',
34 'embeds',
35 'mentions',
36 'mention_roles',
37 'pinned',
38 'mention_everyone',
39 'tts',
40 'timestamp',
41 'edited_timestamp',
42 'flags',
43 'components',
44 'nonce',
45 'referenced_message',
46 ]
48 def select(self, query: ast.Select) -> Response:
49 """Selects data from the Discord channel.
51 Parameters
52 ----------
53 query : ast.Select
54 Given SQL SELECT query.
56 Returns
57 -------
58 Response
59 Response object representing collected data from Discord.
60 """
62 conditions = extract_comparison_conditions(query.where)
64 params = {}
65 filters = []
66 user_filter_flag = channel_filter_flag = False
67 for op, arg1, arg2 in conditions:
68 if op == 'or':
69 raise NotImplementedError('OR is not supported')
70 if arg1 == 'timestamp':
71 if op == '>':
72 params['after'] = arg2
73 elif op == '<':
74 params['before'] = arg2
75 else:
76 raise NotImplementedError(
77 f'Unsupported operator {op} for timestamp'
78 )
80 elif arg1 in ['author_id', 'author_username', 'author_global_name']:
81 if user_filter_flag:
82 raise NotImplementedError('Multiple user filters are not supported')
83 user_filter_flag = True
85 if op != '=':
86 raise NotImplementedError(f'Unsupported operator {op} for {arg1}')
88 # if arg1 == 'author_id':
89 # filters.append(lambda x: x.author.id == int(arg2))
90 # elif arg1 == 'author_username':
91 # filters.append(lambda x: x.author.username == arg2)
92 # elif arg1 == 'author_global_name':
93 # filters.append(lambda x: x.author.global_name == arg2)
95 elif arg1 == 'channel_id':
96 if op != '=':
97 raise NotImplementedError(f'Unsupported operator {op} for {arg1}')
98 channel_filter_flag = True
99 params['channel_id'] = int(arg2)
101 else:
102 filters.append([op, arg1, arg2])
104 if query.limit is not None:
105 params['limit'] = query.limit
106 else:
107 params['limit'] = 100
109 if not channel_filter_flag:
110 raise NotImplementedError('Channel filter is required')
112 result = self.handler.call_discord_api(
113 'get_messages', params=params, filters=filters
114 )
116 # filter targets
117 columns = []
118 for target in query.targets:
119 if isinstance(target, ast.Star):
120 columns = []
121 break
122 elif isinstance(target, ast.Identifier):
123 columns.append(target.parts[-1])
124 else:
125 raise NotImplementedError
127 if len(columns) == 0:
128 columns = self.get_columns()
130 # columns to lower case
131 columns = [name.lower() for name in columns]
133 if len(result) == 0:
134 result = pd.DataFrame([], columns=columns)
135 else:
136 # add absent columns
137 for col in set(columns) & set(result.columns) ^ set(columns):
138 result[col] = None
140 # filter by columns
141 result = result[columns]
142 return result
144 def insert(self, query: ast.Insert) -> None:
145 """Sends messages to a Discord channel.
147 Parameters
148 ----------
149 query : ast.Insert
150 Given SQL INSERT query.
152 Returns
153 -------
154 None
156 Raises
157 ------
158 ValueError
159 If the query contains an unsupported condition
160 """
161 insert_statement_parser = INSERTQueryParser(
162 query,
163 supported_columns=['channel_id', 'text'],
164 mandatory_columns=['channel_id', 'text'],
165 all_mandatory=False,
166 )
167 message_data = insert_statement_parser.parse_query()
168 self.send_message(message_data)
170 def send_message(self, message_data: List[Dict[Text, Any]]) -> None:
171 """Sends messages to a Discord Channel using the parsed message data.
173 Parameters
174 ----------
175 message_data : List[Dict[Text, Any]]
176 List of dictionaries containing the messages to send.
178 Returns
179 -------
180 None
181 """
182 for message in message_data:
183 try:
184 params = {'channel_id': message['channel_id'], 'text': message['text']}
185 self.handler.call_discord_api('send_message', params=params)
186 logger.info("Message sent to Discord channel successfully.")
187 except Exception as e:
188 logger.error(f"Error sending message to Discord channel: {e}")
189 raise e