MindsDB 25.3.4.0__py3-none-any.whl → 25.3.4.2__py3-none-any.whl
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.
Potentially problematic release.
This version of MindsDB might be problematic. Click here for more details.
- mindsdb/__about__.py +2 -2
- mindsdb/api/executor/datahub/datanodes/integration_datanode.py +5 -2
- mindsdb/api/executor/datahub/datanodes/system_tables.py +131 -138
- mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +74 -0
- mindsdb/integrations/handlers/confluence_handler/confluence_api_client.py +176 -0
- mindsdb/integrations/handlers/confluence_handler/confluence_handler.py +54 -59
- mindsdb/integrations/handlers/confluence_handler/confluence_tables.py +753 -0
- mindsdb/integrations/handlers/confluence_handler/connection_args.py +8 -8
- mindsdb/integrations/handlers/langchain_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/lightwood_handler/requirements.txt +3 -3
- mindsdb/integrations/handlers/litellm_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/llama_index_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/ms_teams_handler/ms_graph_api_teams_client.py +278 -55
- mindsdb/integrations/handlers/ms_teams_handler/ms_teams_handler.py +52 -21
- mindsdb/integrations/handlers/ms_teams_handler/ms_teams_tables.py +6 -29
- mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +37 -1
- mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +30 -1
- mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +53 -5
- mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +37 -1
- mindsdb/integrations/handlers/ray_serve_handler/ray_serve_handler.py +18 -16
- mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +68 -2
- mindsdb/integrations/utilities/handlers/auth_utilities/__init__.py +1 -1
- mindsdb/integrations/utilities/handlers/auth_utilities/microsoft/__init__.py +1 -1
- mindsdb/integrations/utilities/handlers/auth_utilities/microsoft/ms_graph_api_auth_utilities.py +97 -18
- mindsdb/utilities/render/sqlalchemy_render.py +30 -6
- {mindsdb-25.3.4.0.dist-info → mindsdb-25.3.4.2.dist-info}/METADATA +226 -231
- {mindsdb-25.3.4.0.dist-info → mindsdb-25.3.4.2.dist-info}/RECORD +30 -30
- {mindsdb-25.3.4.0.dist-info → mindsdb-25.3.4.2.dist-info}/WHEEL +1 -1
- mindsdb/integrations/handlers/confluence_handler/confluence_table.py +0 -193
- mindsdb/integrations/handlers/confluence_handler/requirements.txt +0 -1
- {mindsdb-25.3.4.0.dist-info → mindsdb-25.3.4.2.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.3.4.0.dist-info → mindsdb-25.3.4.2.dist-info}/top_level.txt +0 -0
mindsdb/__about__.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
__title__ = 'MindsDB'
|
|
2
2
|
__package_name__ = 'mindsdb'
|
|
3
|
-
__version__ = '25.3.4.
|
|
3
|
+
__version__ = '25.3.4.2'
|
|
4
4
|
__description__ = "MindsDB's AI SQL Server enables developers to build AI tools that need access to real-time data to perform their tasks"
|
|
5
5
|
__email__ = "jorge@mindsdb.com"
|
|
6
6
|
__author__ = 'MindsDB Inc'
|
|
7
7
|
__github__ = 'https://github.com/mindsdb/mindsdb'
|
|
8
8
|
__pypi__ = 'https://pypi.org/project/mindsdb/'
|
|
9
|
-
__license__ = '
|
|
9
|
+
__license__ = 'Elastic License 2.0'
|
|
10
10
|
__copyright__ = 'Copyright(c) 2018 MindsDB, Inc'
|
|
@@ -64,6 +64,7 @@ class IntegrationDataNode(DataNode):
|
|
|
64
64
|
df = response.data_frame
|
|
65
65
|
# case independent
|
|
66
66
|
columns = [str(c).lower() for c in df.columns]
|
|
67
|
+
df.columns = columns
|
|
67
68
|
|
|
68
69
|
col_name = None
|
|
69
70
|
# looking for specific column names
|
|
@@ -78,8 +79,10 @@ class IntegrationDataNode(DataNode):
|
|
|
78
79
|
names = df[df.columns[col_name]]
|
|
79
80
|
|
|
80
81
|
# type
|
|
81
|
-
if '
|
|
82
|
-
types = df[
|
|
82
|
+
if 'mysql_data_type' in columns:
|
|
83
|
+
types = df['mysql_data_type']
|
|
84
|
+
elif 'type' in columns:
|
|
85
|
+
types = df['type']
|
|
83
86
|
else:
|
|
84
87
|
types = [None] * len(names)
|
|
85
88
|
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
from typing import Optional, Literal
|
|
2
|
+
from dataclasses import dataclass, astuple, fields
|
|
1
3
|
|
|
2
4
|
import pandas as pd
|
|
3
5
|
from mindsdb_sql_parser.ast.base import ASTNode
|
|
4
|
-
from mindsdb.integrations.utilities.sql_utils import extract_comparison_conditions
|
|
5
6
|
|
|
7
|
+
from mindsdb.utilities import log
|
|
8
|
+
from mindsdb.utilities.config import config
|
|
9
|
+
from mindsdb.integrations.utilities.sql_utils import extract_comparison_conditions
|
|
10
|
+
from mindsdb.api.mysql.mysql_proxy.libs.constants.mysql import MYSQL_DATA_TYPE
|
|
6
11
|
from mindsdb.api.executor.datahub.classes.tables_row import (
|
|
7
12
|
TABLES_ROW_TYPE,
|
|
8
13
|
TablesRow,
|
|
9
14
|
)
|
|
10
|
-
from mindsdb.utilities import log
|
|
11
|
-
from mindsdb.utilities.config import config
|
|
12
15
|
|
|
13
16
|
logger = log.getLogger(__name__)
|
|
14
17
|
|
|
@@ -162,132 +165,108 @@ class TablesTable(Table):
|
|
|
162
165
|
return df
|
|
163
166
|
|
|
164
167
|
|
|
165
|
-
|
|
168
|
+
@dataclass
|
|
169
|
+
class ColumnsTableRow:
|
|
170
|
+
"""Represents a row in the COLUMNS table.
|
|
171
|
+
Fields description: https://dev.mysql.com/doc/refman/8.4/en/information-schema-columns-table.html
|
|
172
|
+
NOTE: attrs order matter, don't change it.
|
|
173
|
+
"""
|
|
174
|
+
TABLE_CATALOG: Literal['def'] = 'def'
|
|
175
|
+
TABLE_SCHEMA: Optional[str] = None
|
|
176
|
+
TABLE_NAME: Optional[str] = None
|
|
177
|
+
COLUMN_NAME: Optional[str] = None
|
|
178
|
+
ORDINAL_POSITION: int = 0
|
|
179
|
+
COLUMN_DEFAULT: Optional[str] = None
|
|
180
|
+
IS_NULLABLE: Literal['YES', 'NO'] = 'YES'
|
|
181
|
+
DATA_TYPE: str = MYSQL_DATA_TYPE.VARCHAR.value
|
|
182
|
+
CHARACTER_MAXIMUM_LENGTH: Optional[int] = None
|
|
183
|
+
CHARACTER_OCTET_LENGTH: Optional[int] = None
|
|
184
|
+
NUMERIC_PRECISION: Optional[int] = None
|
|
185
|
+
NUMERIC_SCALE: Optional[int] = None
|
|
186
|
+
DATETIME_PRECISION: Optional[int] = None
|
|
187
|
+
CHARACTER_SET_NAME: Optional[str] = None
|
|
188
|
+
COLLATION_NAME: Optional[str] = None
|
|
189
|
+
COLUMN_TYPE: Optional[str] = None
|
|
190
|
+
COLUMN_KEY: Optional[str] = None
|
|
191
|
+
EXTRA: Optional[str] = None
|
|
192
|
+
PRIVILEGES: str = 'select'
|
|
193
|
+
COLUMN_COMMENT: Optional[str] = None
|
|
194
|
+
GENERATION_EXPRESSION: Optional[str] = None
|
|
195
|
+
|
|
196
|
+
def __post_init__(self):
|
|
197
|
+
# region check mandatory fields
|
|
198
|
+
mandatory_fields = ['TABLE_SCHEMA', 'TABLE_NAME', 'COLUMN_NAME']
|
|
199
|
+
if any(getattr(self, field_name) is None for field_name in mandatory_fields):
|
|
200
|
+
raise ValueError('One of mandatory fields is missed when creating ColumnsTableRow')
|
|
201
|
+
# endregion
|
|
202
|
+
|
|
203
|
+
# region set default values depend on type
|
|
204
|
+
defaults = {
|
|
205
|
+
'COLUMN_TYPE': self.DATA_TYPE
|
|
206
|
+
}
|
|
207
|
+
if MYSQL_DATA_TYPE(self.DATA_TYPE) in (
|
|
208
|
+
MYSQL_DATA_TYPE.TIMESTAMP,
|
|
209
|
+
MYSQL_DATA_TYPE.DATETIME,
|
|
210
|
+
MYSQL_DATA_TYPE.DATE
|
|
211
|
+
):
|
|
212
|
+
defaults = {
|
|
213
|
+
'DATETIME_PRECISION': 0,
|
|
214
|
+
'COLUMN_TYPE': self.DATA_TYPE
|
|
215
|
+
}
|
|
216
|
+
elif MYSQL_DATA_TYPE(self.DATA_TYPE) in (
|
|
217
|
+
MYSQL_DATA_TYPE.FLOAT,
|
|
218
|
+
MYSQL_DATA_TYPE.DOUBLE,
|
|
219
|
+
MYSQL_DATA_TYPE.DECIMAL
|
|
220
|
+
):
|
|
221
|
+
defaults = {
|
|
222
|
+
'NUMERIC_PRECISION': 12,
|
|
223
|
+
'NUMERIC_SCALE': 0,
|
|
224
|
+
'COLUMN_TYPE': self.DATA_TYPE
|
|
225
|
+
}
|
|
226
|
+
elif MYSQL_DATA_TYPE(self.DATA_TYPE) in (
|
|
227
|
+
MYSQL_DATA_TYPE.TINYINT,
|
|
228
|
+
MYSQL_DATA_TYPE.SMALLINT,
|
|
229
|
+
MYSQL_DATA_TYPE.MEDIUMINT,
|
|
230
|
+
MYSQL_DATA_TYPE.INT,
|
|
231
|
+
MYSQL_DATA_TYPE.BIGINT
|
|
232
|
+
):
|
|
233
|
+
defaults = {
|
|
234
|
+
'NUMERIC_PRECISION': 20,
|
|
235
|
+
'NUMERIC_SCALE': 0,
|
|
236
|
+
'COLUMN_TYPE': self.DATA_TYPE
|
|
237
|
+
}
|
|
238
|
+
elif MYSQL_DATA_TYPE(self.DATA_TYPE) is MYSQL_DATA_TYPE.VARCHAR:
|
|
239
|
+
defaults = {
|
|
240
|
+
'CHARACTER_MAXIMUM_LENGTH': 1024,
|
|
241
|
+
'CHARACTER_OCTET_LENGTH': 3072,
|
|
242
|
+
'CHARACTER_SET_NAME': 'utf8',
|
|
243
|
+
'COLLATION_NAME': 'utf8_bin',
|
|
244
|
+
'COLUMN_TYPE': 'varchar(1024)'
|
|
245
|
+
}
|
|
246
|
+
else:
|
|
247
|
+
# show as MYSQL_DATA_TYPE.TEXT:
|
|
248
|
+
defaults = {
|
|
249
|
+
'CHARACTER_MAXIMUM_LENGTH': 65535, # from https://bugs.mysql.com/bug.php?id=90685
|
|
250
|
+
'CHARACTER_OCTET_LENGTH': 65535, #
|
|
251
|
+
'CHARACTER_SET_NAME': 'utf8',
|
|
252
|
+
'COLLATION_NAME': 'utf8_bin',
|
|
253
|
+
'COLUMN_TYPE': 'text'
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
for key, value in defaults.items():
|
|
257
|
+
setattr(self, key, value)
|
|
166
258
|
|
|
259
|
+
self.DATA_TYPE = self.DATA_TYPE.lower()
|
|
260
|
+
self.COLUMN_TYPE = self.COLUMN_TYPE.lower()
|
|
261
|
+
# endregion
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class ColumnsTable(Table):
|
|
167
265
|
name = 'COLUMNS'
|
|
168
|
-
columns = [
|
|
169
|
-
"TABLE_CATALOG",
|
|
170
|
-
"TABLE_SCHEMA",
|
|
171
|
-
"TABLE_NAME",
|
|
172
|
-
"COLUMN_NAME",
|
|
173
|
-
"ORDINAL_POSITION",
|
|
174
|
-
"COLUMN_DEFAULT",
|
|
175
|
-
"IS_NULLABLE",
|
|
176
|
-
"DATA_TYPE",
|
|
177
|
-
"CHARACTER_MAXIMUM_LENGTH",
|
|
178
|
-
"CHARACTER_OCTET_LENGTH",
|
|
179
|
-
"NUMERIC_PRECISION",
|
|
180
|
-
"NUMERIC_SCALE",
|
|
181
|
-
"DATETIME_PRECISION",
|
|
182
|
-
"CHARACTER_SET_NAME",
|
|
183
|
-
"COLLATION_NAME",
|
|
184
|
-
"COLUMN_TYPE",
|
|
185
|
-
"COLUMN_KEY",
|
|
186
|
-
"EXTRA",
|
|
187
|
-
"PRIVILEGES",
|
|
188
|
-
"COLUMN_COMMENT",
|
|
189
|
-
"GENERATION_EXPRESSION",
|
|
190
|
-
]
|
|
266
|
+
columns = [field.name for field in fields(ColumnsTableRow)]
|
|
191
267
|
|
|
192
268
|
@classmethod
|
|
193
269
|
def get_data(cls, inf_schema=None, query: ASTNode = None, **kwargs):
|
|
194
|
-
|
|
195
|
-
# NOTE there is a lot of types in mysql, but listed below should be enough for our purposes
|
|
196
|
-
row_templates = {
|
|
197
|
-
"text": [
|
|
198
|
-
"def",
|
|
199
|
-
"SCHEMA_NAME",
|
|
200
|
-
"TABLE_NAME",
|
|
201
|
-
"COLUMN_NAME",
|
|
202
|
-
"COL_INDEX",
|
|
203
|
-
None,
|
|
204
|
-
"YES",
|
|
205
|
-
"varchar",
|
|
206
|
-
1024,
|
|
207
|
-
3072,
|
|
208
|
-
None,
|
|
209
|
-
None,
|
|
210
|
-
None,
|
|
211
|
-
"utf8",
|
|
212
|
-
"utf8_bin",
|
|
213
|
-
"varchar(1024)",
|
|
214
|
-
None,
|
|
215
|
-
None,
|
|
216
|
-
"select",
|
|
217
|
-
None,
|
|
218
|
-
None,
|
|
219
|
-
],
|
|
220
|
-
"timestamp": [
|
|
221
|
-
"def",
|
|
222
|
-
"SCHEMA_NAME",
|
|
223
|
-
"TABLE_NAME",
|
|
224
|
-
"COLUMN_NAME",
|
|
225
|
-
"COL_INDEX",
|
|
226
|
-
"CURRENT_TIMESTAMP",
|
|
227
|
-
"YES",
|
|
228
|
-
"timestamp",
|
|
229
|
-
None,
|
|
230
|
-
None,
|
|
231
|
-
None,
|
|
232
|
-
None,
|
|
233
|
-
0,
|
|
234
|
-
None,
|
|
235
|
-
None,
|
|
236
|
-
"timestamp",
|
|
237
|
-
None,
|
|
238
|
-
None,
|
|
239
|
-
"select",
|
|
240
|
-
None,
|
|
241
|
-
None,
|
|
242
|
-
],
|
|
243
|
-
"bigint": [
|
|
244
|
-
"def",
|
|
245
|
-
"SCHEMA_NAME",
|
|
246
|
-
"TABLE_NAME",
|
|
247
|
-
"COLUMN_NAME",
|
|
248
|
-
"COL_INDEX",
|
|
249
|
-
None,
|
|
250
|
-
"YES",
|
|
251
|
-
"bigint",
|
|
252
|
-
None,
|
|
253
|
-
None,
|
|
254
|
-
20,
|
|
255
|
-
0,
|
|
256
|
-
None,
|
|
257
|
-
None,
|
|
258
|
-
None,
|
|
259
|
-
"bigint unsigned",
|
|
260
|
-
None,
|
|
261
|
-
None,
|
|
262
|
-
"select",
|
|
263
|
-
None,
|
|
264
|
-
None,
|
|
265
|
-
],
|
|
266
|
-
"float": [
|
|
267
|
-
"def",
|
|
268
|
-
"SCHEMA_NAME",
|
|
269
|
-
"TABLE_NAME",
|
|
270
|
-
"COLUMN_NAME",
|
|
271
|
-
"COL_INDEX",
|
|
272
|
-
None,
|
|
273
|
-
"YES",
|
|
274
|
-
"float",
|
|
275
|
-
None,
|
|
276
|
-
None,
|
|
277
|
-
12,
|
|
278
|
-
0,
|
|
279
|
-
None,
|
|
280
|
-
None,
|
|
281
|
-
None,
|
|
282
|
-
"float",
|
|
283
|
-
None,
|
|
284
|
-
None,
|
|
285
|
-
"select",
|
|
286
|
-
None,
|
|
287
|
-
None,
|
|
288
|
-
],
|
|
289
|
-
}
|
|
290
|
-
|
|
291
270
|
result = []
|
|
292
271
|
|
|
293
272
|
databases, tables_names = _get_scope(query)
|
|
@@ -320,20 +299,34 @@ class ColumnsTable(Table):
|
|
|
320
299
|
for i, column in enumerate(table_columns):
|
|
321
300
|
column_name = column['name']
|
|
322
301
|
column_type = column.get('type', 'text')
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
column_type
|
|
327
|
-
|
|
328
|
-
column_type
|
|
329
|
-
|
|
330
|
-
column_type
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
302
|
+
|
|
303
|
+
# region infer type
|
|
304
|
+
if isinstance(column_type, MYSQL_DATA_TYPE) is False:
|
|
305
|
+
if column_type in ('double precision', 'real', 'numeric', 'float'):
|
|
306
|
+
column_type = MYSQL_DATA_TYPE.FLOAT
|
|
307
|
+
elif column_type in ('integer', 'smallint', 'int', 'bigint'):
|
|
308
|
+
column_type = MYSQL_DATA_TYPE.BIGINT
|
|
309
|
+
elif column_type in (
|
|
310
|
+
'timestamp without time zone',
|
|
311
|
+
'timestamp with time zone',
|
|
312
|
+
'date', 'timestamp'
|
|
313
|
+
):
|
|
314
|
+
column_type = MYSQL_DATA_TYPE.DATETIME
|
|
315
|
+
else:
|
|
316
|
+
column_type = MYSQL_DATA_TYPE.VARCHAR
|
|
317
|
+
# endregion
|
|
318
|
+
|
|
319
|
+
column_row = astuple(
|
|
320
|
+
ColumnsTableRow(
|
|
321
|
+
TABLE_SCHEMA=db_name,
|
|
322
|
+
TABLE_NAME=table_name,
|
|
323
|
+
COLUMN_NAME=column_name,
|
|
324
|
+
DATA_TYPE=column_type.value,
|
|
325
|
+
ORDINAL_POSITION=i
|
|
326
|
+
)
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
result.append(column_row)
|
|
337
330
|
|
|
338
331
|
df = pd.DataFrame(result, columns=cls.columns)
|
|
339
332
|
return df
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* permission of MindsDB Inc
|
|
9
9
|
*******************************************************
|
|
10
10
|
"""
|
|
11
|
+
import enum
|
|
11
12
|
|
|
12
13
|
# CAPABILITIES
|
|
13
14
|
# As defined in : https://dev.mysql.com/doc/dev/mysql-server/8.0.0/group__group__cs__capabilities__flags.html
|
|
@@ -101,6 +102,8 @@ COMMANDS = COMMANDS()
|
|
|
101
102
|
|
|
102
103
|
|
|
103
104
|
# FIELD TYPES
|
|
105
|
+
# https://dev.mysql.com/doc/dev/mysql-server/latest/field__types_8h_source.html
|
|
106
|
+
# https://mariadb.com/kb/en/result-set-packets/
|
|
104
107
|
class TYPES(object):
|
|
105
108
|
__slots__ = ()
|
|
106
109
|
MYSQL_TYPE_DECIMAL = 0
|
|
@@ -123,6 +126,11 @@ class TYPES(object):
|
|
|
123
126
|
MYSQL_TYPE_TIMESTAMP2 = 17
|
|
124
127
|
MYSQL_TYPE_DATETIME2 = 18
|
|
125
128
|
MYSQL_TYPE_TIME2 = 19
|
|
129
|
+
MYSQL_TYPE_TYPED_ARRAY = 20
|
|
130
|
+
MYSQL_TYPE_VECTOR = 242,
|
|
131
|
+
MYSQL_TYPE_INVALID = 243,
|
|
132
|
+
MYSQL_TYPE_BOOL = 244,
|
|
133
|
+
MYSQL_TYPE_JSON = 245,
|
|
126
134
|
MYSQL_TYPE_NEWDECIMAL = 246
|
|
127
135
|
MYSQL_TYPE_ENUM = 247
|
|
128
136
|
MYSQL_TYPE_SET = 248
|
|
@@ -135,9 +143,75 @@ class TYPES(object):
|
|
|
135
143
|
MYSQL_TYPE_GEOMETRY = 255
|
|
136
144
|
|
|
137
145
|
|
|
146
|
+
C_TYPES = TYPES()
|
|
138
147
|
TYPES = TYPES()
|
|
139
148
|
|
|
140
149
|
|
|
150
|
+
class MYSQL_DATA_TYPE(enum.Enum):
|
|
151
|
+
TINYINT = 'TINYINT'
|
|
152
|
+
SMALLINT = 'SMALLINT'
|
|
153
|
+
MEDIUMINT = 'MEDIUMINT'
|
|
154
|
+
INT = 'INT'
|
|
155
|
+
BIGINT = 'BIGINT'
|
|
156
|
+
FLOAT = 'FLOAT'
|
|
157
|
+
DOUBLE = 'DOUBLE'
|
|
158
|
+
DECIMAL = 'DECIMAL'
|
|
159
|
+
YEAR = 'YEAR'
|
|
160
|
+
TIME = 'TIME'
|
|
161
|
+
DATE = 'DATE'
|
|
162
|
+
DATETIME = 'DATETIME'
|
|
163
|
+
TIMESTAMP = 'TIMESTAMP'
|
|
164
|
+
CHAR = 'CHAR'
|
|
165
|
+
BINARY = 'BINARY'
|
|
166
|
+
VARCHAR = 'VARCHAR'
|
|
167
|
+
VARBINARY = 'VARBINARY'
|
|
168
|
+
TINYBLOB = 'TINYBLOB'
|
|
169
|
+
TINYTEXT = 'TINYTEXT'
|
|
170
|
+
BLOB = 'BLOB'
|
|
171
|
+
TEXT = 'TEXT'
|
|
172
|
+
MEDIUMBLOB = 'MEDIUMBLOB'
|
|
173
|
+
MEDIUMTEXT = 'MEDIUMTEXT'
|
|
174
|
+
LONGBLOB = 'LONGBLOB'
|
|
175
|
+
LONGTEXT = 'LONGTEXT'
|
|
176
|
+
BIT = 'BIT'
|
|
177
|
+
BOOL = 'BOOL'
|
|
178
|
+
BOOLEAN = 'BOOLEAN'
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# Map between data types and C types
|
|
182
|
+
# https://dev.mysql.com/doc/c-api/8.0/en/c-api-prepared-statement-type-codes.html
|
|
183
|
+
DATA_C_TYPE_MAP = {
|
|
184
|
+
MYSQL_DATA_TYPE.TINYINT: C_TYPES.MYSQL_TYPE_TINY,
|
|
185
|
+
MYSQL_DATA_TYPE.SMALLINT: C_TYPES.MYSQL_TYPE_SHORT,
|
|
186
|
+
MYSQL_DATA_TYPE.MEDIUMINT: C_TYPES.MYSQL_TYPE_INT24,
|
|
187
|
+
MYSQL_DATA_TYPE.INT: C_TYPES.MYSQL_TYPE_LONG,
|
|
188
|
+
MYSQL_DATA_TYPE.BIGINT: C_TYPES.MYSQL_TYPE_LONGLONG,
|
|
189
|
+
MYSQL_DATA_TYPE.FLOAT: C_TYPES.MYSQL_TYPE_FLOAT,
|
|
190
|
+
MYSQL_DATA_TYPE.DOUBLE: C_TYPES.MYSQL_TYPE_DOUBLE,
|
|
191
|
+
MYSQL_DATA_TYPE.DECIMAL: C_TYPES.MYSQL_TYPE_NEWDECIMAL,
|
|
192
|
+
MYSQL_DATA_TYPE.YEAR: C_TYPES.MYSQL_TYPE_SHORT,
|
|
193
|
+
MYSQL_DATA_TYPE.TIME: C_TYPES.MYSQL_TYPE_TIME,
|
|
194
|
+
MYSQL_DATA_TYPE.DATE: C_TYPES.MYSQL_TYPE_DATE,
|
|
195
|
+
MYSQL_DATA_TYPE.DATETIME: C_TYPES.MYSQL_TYPE_DATETIME,
|
|
196
|
+
MYSQL_DATA_TYPE.TIMESTAMP: C_TYPES.MYSQL_TYPE_TIMESTAMP,
|
|
197
|
+
MYSQL_DATA_TYPE.CHAR: C_TYPES.MYSQL_TYPE_STRING,
|
|
198
|
+
MYSQL_DATA_TYPE.BINARY: C_TYPES.MYSQL_TYPE_STRING,
|
|
199
|
+
MYSQL_DATA_TYPE.VARCHAR: C_TYPES.MYSQL_TYPE_VAR_STRING,
|
|
200
|
+
MYSQL_DATA_TYPE.VARBINARY: C_TYPES.MYSQL_TYPE_VAR_STRING,
|
|
201
|
+
MYSQL_DATA_TYPE.TINYBLOB: C_TYPES.MYSQL_TYPE_TINY_BLOB,
|
|
202
|
+
MYSQL_DATA_TYPE.TINYTEXT: C_TYPES.MYSQL_TYPE_TINY_BLOB,
|
|
203
|
+
MYSQL_DATA_TYPE.BLOB: C_TYPES.MYSQL_TYPE_BLOB,
|
|
204
|
+
MYSQL_DATA_TYPE.TEXT: C_TYPES.MYSQL_TYPE_BLOB,
|
|
205
|
+
MYSQL_DATA_TYPE.MEDIUMBLOB: C_TYPES.MYSQL_TYPE_MEDIUM_BLOB,
|
|
206
|
+
MYSQL_DATA_TYPE.MEDIUMTEXT: C_TYPES.MYSQL_TYPE_MEDIUM_BLOB,
|
|
207
|
+
MYSQL_DATA_TYPE.LONGBLOB: C_TYPES.MYSQL_TYPE_LONG_BLOB,
|
|
208
|
+
MYSQL_DATA_TYPE.LONGTEXT: C_TYPES.MYSQL_TYPE_LONG_BLOB,
|
|
209
|
+
MYSQL_DATA_TYPE.BIT: C_TYPES.MYSQL_TYPE_BIT,
|
|
210
|
+
MYSQL_DATA_TYPE.BOOL: C_TYPES.MYSQL_TYPE_TINY,
|
|
211
|
+
MYSQL_DATA_TYPE.BOOLEAN: C_TYPES.MYSQL_TYPE_TINY
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
|
141
215
|
class FIELD_FLAG(object):
|
|
142
216
|
__slots__ = ()
|
|
143
217
|
NOT_NULL = 1 # field cannot be null
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ConfluenceAPIClient:
|
|
7
|
+
def __init__(self, url: str, username: str, password: str):
|
|
8
|
+
self.url = url
|
|
9
|
+
self.username = username
|
|
10
|
+
self.password = password
|
|
11
|
+
self.session = requests.Session()
|
|
12
|
+
self.session.auth = (self.username, self.password)
|
|
13
|
+
self.session.headers.update({"Accept": "application/json"})
|
|
14
|
+
|
|
15
|
+
def get_spaces(
|
|
16
|
+
self,
|
|
17
|
+
ids: List[int] = None,
|
|
18
|
+
keys: List[str] = None,
|
|
19
|
+
space_type: str = None,
|
|
20
|
+
status: str = None,
|
|
21
|
+
sort_condition: str = None,
|
|
22
|
+
limit: int = None,
|
|
23
|
+
):
|
|
24
|
+
url = f"{self.url}/wiki/api/v2/spaces"
|
|
25
|
+
params = {
|
|
26
|
+
"description-format": "view",
|
|
27
|
+
}
|
|
28
|
+
if ids:
|
|
29
|
+
params["ids"] = ids
|
|
30
|
+
if keys:
|
|
31
|
+
params["keys"] = keys
|
|
32
|
+
if space_type:
|
|
33
|
+
params["type"] = space_type
|
|
34
|
+
if status:
|
|
35
|
+
params["status"] = status
|
|
36
|
+
if sort_condition:
|
|
37
|
+
params["sort"] = sort_condition
|
|
38
|
+
if limit:
|
|
39
|
+
params["limit"] = limit
|
|
40
|
+
|
|
41
|
+
return self._paginate(url, params)
|
|
42
|
+
|
|
43
|
+
def get_pages(
|
|
44
|
+
self,
|
|
45
|
+
page_ids: List[int] = None,
|
|
46
|
+
space_ids: List[int] = None,
|
|
47
|
+
statuses: List[str] = None,
|
|
48
|
+
title: str = None,
|
|
49
|
+
sort_condition: str = None,
|
|
50
|
+
limit: int = None,
|
|
51
|
+
) -> List[dict]:
|
|
52
|
+
url = f"{self.url}/wiki/api/v2/pages"
|
|
53
|
+
params = {
|
|
54
|
+
"body-format": "storage",
|
|
55
|
+
}
|
|
56
|
+
if page_ids:
|
|
57
|
+
params["id"] = page_ids
|
|
58
|
+
if space_ids:
|
|
59
|
+
params["space-id"] = space_ids
|
|
60
|
+
if statuses:
|
|
61
|
+
params["status"] = statuses
|
|
62
|
+
if title:
|
|
63
|
+
params["title"] = title
|
|
64
|
+
if sort_condition:
|
|
65
|
+
params["sort"] = sort_condition
|
|
66
|
+
if limit:
|
|
67
|
+
params["limit"] = limit
|
|
68
|
+
|
|
69
|
+
return self._paginate(url, params)
|
|
70
|
+
|
|
71
|
+
def get_blogposts(
|
|
72
|
+
self,
|
|
73
|
+
post_ids: List[int] = None,
|
|
74
|
+
space_ids: List[str] = None,
|
|
75
|
+
statuses: List[str] = None,
|
|
76
|
+
title: str = None,
|
|
77
|
+
sort_condition: str = None,
|
|
78
|
+
limit: int = None,
|
|
79
|
+
) -> List[dict]:
|
|
80
|
+
url = f"{self.url}/wiki/api/v2/blogposts"
|
|
81
|
+
params = {
|
|
82
|
+
"body-format": "storage",
|
|
83
|
+
}
|
|
84
|
+
if post_ids:
|
|
85
|
+
params["id"] = post_ids
|
|
86
|
+
if space_ids:
|
|
87
|
+
params["space-id"] = space_ids
|
|
88
|
+
if statuses:
|
|
89
|
+
params["status"] = statuses
|
|
90
|
+
if title:
|
|
91
|
+
params["title"] = title
|
|
92
|
+
if sort_condition:
|
|
93
|
+
params["sort"] = sort_condition
|
|
94
|
+
if limit:
|
|
95
|
+
params["limit"] = limit
|
|
96
|
+
|
|
97
|
+
return self._paginate(url, params)
|
|
98
|
+
|
|
99
|
+
def get_whiteboard_by_id(self, whiteboard_id: int) -> dict:
|
|
100
|
+
url = f"{self.url}/wiki/api/v2/whiteboards/{whiteboard_id}"
|
|
101
|
+
|
|
102
|
+
return self._make_request("GET", url)
|
|
103
|
+
|
|
104
|
+
def get_database_by_id(self, database_id: int) -> dict:
|
|
105
|
+
url = f"{self.url}/wiki/api/v2/databases/{database_id}"
|
|
106
|
+
|
|
107
|
+
return self._make_request("GET", url)
|
|
108
|
+
|
|
109
|
+
def get_tasks(
|
|
110
|
+
self,
|
|
111
|
+
task_ids: List[int] = None,
|
|
112
|
+
space_ids: List[str] = None,
|
|
113
|
+
page_ids: List[str] = None,
|
|
114
|
+
blogpost_ids: List[str] = None,
|
|
115
|
+
created_by_ids: List[str] = None,
|
|
116
|
+
assigned_to_ids: List[str] = None,
|
|
117
|
+
completed_by_ids: List[str] = None,
|
|
118
|
+
status: str = None,
|
|
119
|
+
limit: int = None,
|
|
120
|
+
) -> List[dict]:
|
|
121
|
+
url = f"{self.url}/wiki/api/v2/tasks"
|
|
122
|
+
params = {
|
|
123
|
+
"body-format": "storage",
|
|
124
|
+
}
|
|
125
|
+
if task_ids:
|
|
126
|
+
params["id"] = task_ids
|
|
127
|
+
if space_ids:
|
|
128
|
+
params["space-id"] = space_ids
|
|
129
|
+
if page_ids:
|
|
130
|
+
params["page-id"] = page_ids
|
|
131
|
+
if blogpost_ids:
|
|
132
|
+
params["blogpost-id"] = blogpost_ids
|
|
133
|
+
if created_by_ids:
|
|
134
|
+
params["created-by"] = created_by_ids
|
|
135
|
+
if assigned_to_ids:
|
|
136
|
+
params["assigned-to"] = assigned_to_ids
|
|
137
|
+
if completed_by_ids:
|
|
138
|
+
params["completed-by"] = completed_by_ids
|
|
139
|
+
if status:
|
|
140
|
+
params["status"] = status
|
|
141
|
+
if limit:
|
|
142
|
+
params["limit"] = limit
|
|
143
|
+
|
|
144
|
+
return self._paginate(url, params)
|
|
145
|
+
|
|
146
|
+
def _paginate(self, url: str, params: dict = None) -> List[dict]:
|
|
147
|
+
results = []
|
|
148
|
+
response = self._make_request("GET", url, params)
|
|
149
|
+
results.extend(response["results"])
|
|
150
|
+
|
|
151
|
+
while response["_links"].get("next"):
|
|
152
|
+
next_url = response["_links"].get("next")
|
|
153
|
+
next_params = {}
|
|
154
|
+
if params:
|
|
155
|
+
next_params.update(params)
|
|
156
|
+
if "cursor=" in next_url:
|
|
157
|
+
# cursor= is 7 characters long
|
|
158
|
+
cursor_start = next_url.find("cursor=") + 7
|
|
159
|
+
cursor_value = next_url[cursor_start:]
|
|
160
|
+
if "&" in cursor_value:
|
|
161
|
+
cursor_value = cursor_value.split("&")[0]
|
|
162
|
+
next_params["cursor"] = cursor_value
|
|
163
|
+
response = self._make_request("GET", url, next_params)
|
|
164
|
+
else:
|
|
165
|
+
response = self._make_request("GET", next_url)
|
|
166
|
+
results.extend(response["results"])
|
|
167
|
+
|
|
168
|
+
return results
|
|
169
|
+
|
|
170
|
+
def _make_request(self, method: str, url: str, params: dict = None, data: dict = None) -> dict:
|
|
171
|
+
response = self.session.request(method, url, params=params, json=data)
|
|
172
|
+
|
|
173
|
+
if response.status_code != 200:
|
|
174
|
+
raise Exception(f"Request failed with status code {response.status_code}: {response.text}")
|
|
175
|
+
|
|
176
|
+
return response.json()
|