matrixone-python-sdk 0.1.0__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.
- matrixone/__init__.py +155 -0
- matrixone/account.py +723 -0
- matrixone/async_client.py +3913 -0
- matrixone/async_metadata_manager.py +311 -0
- matrixone/async_orm.py +123 -0
- matrixone/async_vector_index_manager.py +633 -0
- matrixone/base_client.py +208 -0
- matrixone/client.py +4672 -0
- matrixone/config.py +452 -0
- matrixone/connection_hooks.py +286 -0
- matrixone/exceptions.py +89 -0
- matrixone/logger.py +782 -0
- matrixone/metadata.py +820 -0
- matrixone/moctl.py +219 -0
- matrixone/orm.py +2277 -0
- matrixone/pitr.py +646 -0
- matrixone/pubsub.py +771 -0
- matrixone/restore.py +411 -0
- matrixone/search_vector_index.py +1176 -0
- matrixone/snapshot.py +550 -0
- matrixone/sql_builder.py +844 -0
- matrixone/sqlalchemy_ext/__init__.py +161 -0
- matrixone/sqlalchemy_ext/adapters.py +163 -0
- matrixone/sqlalchemy_ext/dialect.py +534 -0
- matrixone/sqlalchemy_ext/fulltext_index.py +895 -0
- matrixone/sqlalchemy_ext/fulltext_search.py +1686 -0
- matrixone/sqlalchemy_ext/hnsw_config.py +194 -0
- matrixone/sqlalchemy_ext/ivf_config.py +252 -0
- matrixone/sqlalchemy_ext/table_builder.py +351 -0
- matrixone/sqlalchemy_ext/vector_index.py +1721 -0
- matrixone/sqlalchemy_ext/vector_type.py +948 -0
- matrixone/version.py +580 -0
- matrixone_python_sdk-0.1.0.dist-info/METADATA +706 -0
- matrixone_python_sdk-0.1.0.dist-info/RECORD +122 -0
- matrixone_python_sdk-0.1.0.dist-info/WHEEL +5 -0
- matrixone_python_sdk-0.1.0.dist-info/entry_points.txt +5 -0
- matrixone_python_sdk-0.1.0.dist-info/licenses/LICENSE +200 -0
- matrixone_python_sdk-0.1.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +19 -0
- tests/offline/__init__.py +20 -0
- tests/offline/conftest.py +77 -0
- tests/offline/test_account.py +703 -0
- tests/offline/test_async_client_query_comprehensive.py +1218 -0
- tests/offline/test_basic.py +54 -0
- tests/offline/test_case_sensitivity.py +227 -0
- tests/offline/test_connection_hooks_offline.py +287 -0
- tests/offline/test_dialect_schema_handling.py +609 -0
- tests/offline/test_explain_methods.py +346 -0
- tests/offline/test_filter_logical_in.py +237 -0
- tests/offline/test_fulltext_search_comprehensive.py +795 -0
- tests/offline/test_ivf_config.py +249 -0
- tests/offline/test_join_methods.py +281 -0
- tests/offline/test_join_sqlalchemy_compatibility.py +276 -0
- tests/offline/test_logical_in_method.py +237 -0
- tests/offline/test_matrixone_version_parsing.py +264 -0
- tests/offline/test_metadata_offline.py +557 -0
- tests/offline/test_moctl.py +300 -0
- tests/offline/test_moctl_simple.py +251 -0
- tests/offline/test_model_support_offline.py +359 -0
- tests/offline/test_model_support_simple.py +225 -0
- tests/offline/test_pinecone_filter_offline.py +377 -0
- tests/offline/test_pitr.py +585 -0
- tests/offline/test_pubsub.py +712 -0
- tests/offline/test_query_update.py +283 -0
- tests/offline/test_restore.py +445 -0
- tests/offline/test_snapshot_comprehensive.py +384 -0
- tests/offline/test_sql_escaping_edge_cases.py +551 -0
- tests/offline/test_sqlalchemy_integration.py +382 -0
- tests/offline/test_sqlalchemy_vector_integration.py +434 -0
- tests/offline/test_table_builder.py +198 -0
- tests/offline/test_unified_filter.py +398 -0
- tests/offline/test_unified_transaction.py +495 -0
- tests/offline/test_vector_index.py +238 -0
- tests/offline/test_vector_operations.py +688 -0
- tests/offline/test_vector_type.py +174 -0
- tests/offline/test_version_core.py +328 -0
- tests/offline/test_version_management.py +372 -0
- tests/offline/test_version_standalone.py +652 -0
- tests/online/__init__.py +20 -0
- tests/online/conftest.py +216 -0
- tests/online/test_account_management.py +194 -0
- tests/online/test_advanced_features.py +344 -0
- tests/online/test_async_client_interfaces.py +330 -0
- tests/online/test_async_client_online.py +285 -0
- tests/online/test_async_model_insert_online.py +293 -0
- tests/online/test_async_orm_online.py +300 -0
- tests/online/test_async_simple_query_online.py +802 -0
- tests/online/test_async_transaction_simple_query.py +300 -0
- tests/online/test_basic_connection.py +130 -0
- tests/online/test_client_online.py +238 -0
- tests/online/test_config.py +90 -0
- tests/online/test_config_validation.py +123 -0
- tests/online/test_connection_hooks_new_online.py +217 -0
- tests/online/test_dialect_schema_handling_online.py +331 -0
- tests/online/test_filter_logical_in_online.py +374 -0
- tests/online/test_fulltext_comprehensive.py +1773 -0
- tests/online/test_fulltext_label_online.py +433 -0
- tests/online/test_fulltext_search_online.py +842 -0
- tests/online/test_ivf_stats_online.py +506 -0
- tests/online/test_logger_integration.py +311 -0
- tests/online/test_matrixone_query_orm.py +540 -0
- tests/online/test_metadata_online.py +579 -0
- tests/online/test_model_insert_online.py +255 -0
- tests/online/test_mysql_driver_validation.py +213 -0
- tests/online/test_orm_advanced_features.py +2022 -0
- tests/online/test_orm_cte_integration.py +269 -0
- tests/online/test_orm_online.py +270 -0
- tests/online/test_pinecone_filter.py +708 -0
- tests/online/test_pubsub_operations.py +352 -0
- tests/online/test_query_methods.py +225 -0
- tests/online/test_query_update_online.py +433 -0
- tests/online/test_search_vector_index.py +557 -0
- tests/online/test_simple_fulltext_online.py +915 -0
- tests/online/test_snapshot_comprehensive.py +998 -0
- tests/online/test_sqlalchemy_engine_integration.py +336 -0
- tests/online/test_sqlalchemy_integration.py +425 -0
- tests/online/test_transaction_contexts.py +1219 -0
- tests/online/test_transaction_insert_methods.py +356 -0
- tests/online/test_transaction_query_methods.py +288 -0
- tests/online/test_unified_filter_online.py +529 -0
- tests/online/test_vector_comprehensive.py +706 -0
- tests/online/test_version_management.py +291 -0
@@ -0,0 +1,534 @@
|
|
1
|
+
# Copyright 2021 - 2022 Matrix Origin
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
"""
|
16
|
+
MatrixOne SQLAlchemy dialect support.
|
17
|
+
"""
|
18
|
+
|
19
|
+
import sqlalchemy
|
20
|
+
from sqlalchemy.dialects.mysql import VARCHAR
|
21
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
22
|
+
|
23
|
+
|
24
|
+
class MatrixOneDialect(MySQLDialect):
|
25
|
+
"""
|
26
|
+
MatrixOne dialect for SQLAlchemy.
|
27
|
+
|
28
|
+
This dialect extends MySQL dialect to support MatrixOne-specific features
|
29
|
+
including vector types (vecf32/vecf64), fulltext search, and other
|
30
|
+
MatrixOne-specific SQL constructs.
|
31
|
+
|
32
|
+
Key Features:
|
33
|
+
|
34
|
+
- Full MySQL compatibility for standard operations
|
35
|
+
- Support for MatrixOne vector types (vecf32, vecf64)
|
36
|
+
- Fulltext search syntax support
|
37
|
+
- MatrixOne-specific error handling
|
38
|
+
- Connection charset configuration
|
39
|
+
- Statement caching support
|
40
|
+
|
41
|
+
Supported MatrixOne Features:
|
42
|
+
- Vector data types and operations
|
43
|
+
- Fulltext indexing and search
|
44
|
+
- Snapshot and PITR operations
|
45
|
+
- Account and user management
|
46
|
+
- Vector similarity search functions
|
47
|
+
|
48
|
+
Usage:
|
49
|
+
|
50
|
+
# Create engine with MatrixOne dialect
|
51
|
+
engine = create_engine(
|
52
|
+
'matrixone://user:password@host:port/database',
|
53
|
+
dialect=MatrixOneDialect()
|
54
|
+
)
|
55
|
+
|
56
|
+
# Or use the dialect name in connection string
|
57
|
+
engine = create_engine('matrixone+mysql://user:password@host:port/database')
|
58
|
+
|
59
|
+
Note: This dialect is automatically used when connecting to MatrixOne
|
60
|
+
databases through the MatrixOne Python client.
|
61
|
+
"""
|
62
|
+
|
63
|
+
name = "matrixone"
|
64
|
+
|
65
|
+
def __init__(self, **kwargs):
|
66
|
+
super().__init__(**kwargs)
|
67
|
+
# Initialize missing MySQL dialect attributes
|
68
|
+
self._connection_charset = "utf8mb4"
|
69
|
+
|
70
|
+
def _extract_error_code(self, exception):
|
71
|
+
"""Extract error code from MatrixOne exceptions."""
|
72
|
+
if hasattr(exception, "args") and len(exception.args) > 0:
|
73
|
+
if isinstance(exception.args[0], int):
|
74
|
+
return exception.args[0]
|
75
|
+
return None
|
76
|
+
|
77
|
+
# MatrixOne supports MySQL-compatible syntax
|
78
|
+
supports_statement_cache = True
|
79
|
+
|
80
|
+
def get_table_names(self, connection, schema=None, **kw):
|
81
|
+
"""Get table names from MatrixOne database."""
|
82
|
+
return super().get_table_names(connection, schema, **kw)
|
83
|
+
|
84
|
+
def has_table(self, connection, table_name, schema=None, **kw):
|
85
|
+
"""Check if table exists in MatrixOne database."""
|
86
|
+
# MatrixOne doesn't use schemas, but MySQL dialect requires schema to be not None
|
87
|
+
# Use current database name as schema to satisfy MySQL dialect requirements
|
88
|
+
if schema is None:
|
89
|
+
# Get current database name from connection URL or connection info
|
90
|
+
try:
|
91
|
+
# Try to get database name from connection URL
|
92
|
+
if hasattr(connection, 'connection') and hasattr(connection.connection, 'get_dsn_parameters'):
|
93
|
+
dsn_params = connection.connection.get_dsn_parameters()
|
94
|
+
schema = dsn_params.get('dbname') or dsn_params.get('database')
|
95
|
+
|
96
|
+
# Fallback: try to get from connection string
|
97
|
+
if not schema and hasattr(connection, 'connection') and hasattr(connection.connection, 'dsn'):
|
98
|
+
dsn = connection.connection.dsn
|
99
|
+
if 'dbname=' in dsn:
|
100
|
+
schema = dsn.split('dbname=')[1].split()[0]
|
101
|
+
elif 'database=' in dsn:
|
102
|
+
schema = dsn.split('database=')[1].split()[0]
|
103
|
+
|
104
|
+
# Final fallback: use default database name
|
105
|
+
if not schema:
|
106
|
+
schema = "test"
|
107
|
+
|
108
|
+
except Exception:
|
109
|
+
# Ultimate fallback
|
110
|
+
schema = "test"
|
111
|
+
|
112
|
+
return super().has_table(connection, table_name, schema, **kw)
|
113
|
+
|
114
|
+
def get_columns(self, connection, table_name, schema=None, **kw):
|
115
|
+
"""Get column information including vector types."""
|
116
|
+
columns = super().get_columns(connection, table_name, schema, **kw)
|
117
|
+
|
118
|
+
# Process vector columns (case-insensitive)
|
119
|
+
for column in columns:
|
120
|
+
if isinstance(column["type"], str):
|
121
|
+
type_str_lower = column["type"].lower()
|
122
|
+
if type_str_lower.startswith("vecf32"):
|
123
|
+
column["type"] = self._create_vector_type("f32", column["type"])
|
124
|
+
elif type_str_lower.startswith("vecf64"):
|
125
|
+
column["type"] = self._create_vector_type("f64", column["type"])
|
126
|
+
|
127
|
+
return columns
|
128
|
+
|
129
|
+
def _create_vector_type(self, precision: str, type_str: str):
|
130
|
+
"""Create appropriate vector type from string."""
|
131
|
+
# Extract dimension from vecf32(128), VECF32(128), vecf64(256), etc.
|
132
|
+
# Handle case-insensitive matching
|
133
|
+
import re
|
134
|
+
|
135
|
+
from .vector_type import VectorType
|
136
|
+
|
137
|
+
# Clean the input string and make it lowercase for pattern matching
|
138
|
+
clean_type_str = type_str.strip().lower()
|
139
|
+
|
140
|
+
# Build pattern dynamically to avoid f-string issues
|
141
|
+
if precision == "f32":
|
142
|
+
pattern = r"vecf32\((\d+)\)"
|
143
|
+
elif precision == "f64":
|
144
|
+
pattern = r"vecf64\((\d+)\)"
|
145
|
+
else:
|
146
|
+
pattern = rf"vecf{precision}\((\d+)\)"
|
147
|
+
|
148
|
+
match = re.search(pattern, clean_type_str)
|
149
|
+
|
150
|
+
if match:
|
151
|
+
try:
|
152
|
+
dimension = int(match.group(1))
|
153
|
+
return VectorType(dimension=dimension, precision=precision)
|
154
|
+
except ValueError:
|
155
|
+
pass
|
156
|
+
|
157
|
+
return VectorType(precision=precision)
|
158
|
+
|
159
|
+
def type_descriptor(self, type_):
|
160
|
+
"""Handle MatrixOne specific types."""
|
161
|
+
if hasattr(type_, "__visit_name__") and type_.__visit_name__ == "VECTOR":
|
162
|
+
return VARCHAR(65535) # Use VARCHAR for vector storage
|
163
|
+
return super().type_descriptor(type_)
|
164
|
+
|
165
|
+
|
166
|
+
class MatrixOneCompiler(MySQLDialect.statement_compiler):
|
167
|
+
"""MatrixOne SQL compiler for handling vector types."""
|
168
|
+
|
169
|
+
def visit_user_defined_type(self, type_, **kw):
|
170
|
+
"""Handle user-defined vector types."""
|
171
|
+
if hasattr(type_, "get_col_spec"):
|
172
|
+
return type_.get_col_spec()
|
173
|
+
return super().visit_user_defined_type(type_, **kw)
|
174
|
+
|
175
|
+
|
176
|
+
# SQLAlchemy version compatibility
|
177
|
+
SA_VERSION = tuple(map(int, sqlalchemy.__version__.split(".")[:2]))
|
178
|
+
|
179
|
+
if SA_VERSION >= (2, 0):
|
180
|
+
# SQLAlchemy 2.0+
|
181
|
+
from sqlalchemy.sql.compiler import TypeCompiler
|
182
|
+
|
183
|
+
class MatrixOneTypeCompiler(TypeCompiler):
|
184
|
+
"""MatrixOne type compiler for handling vector types."""
|
185
|
+
|
186
|
+
def visit_VECTOR(self, type_, **kw):
|
187
|
+
"""Handle VECTOR type compilation."""
|
188
|
+
if hasattr(type_, "get_col_spec"):
|
189
|
+
return type_.get_col_spec()
|
190
|
+
return "VECTOR"
|
191
|
+
|
192
|
+
# Delegate all other types to MySQL type compiler
|
193
|
+
def visit_integer(self, type_, **kw):
|
194
|
+
"""Handle INTEGER type compilation."""
|
195
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
196
|
+
|
197
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
198
|
+
return mysql_compiler.visit_integer(type_, **kw)
|
199
|
+
|
200
|
+
def visit_string(self, type_, **kw):
|
201
|
+
"""Handle STRING type compilation."""
|
202
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
203
|
+
|
204
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
205
|
+
return mysql_compiler.visit_string(type_, **kw)
|
206
|
+
|
207
|
+
def visit_text(self, type_, **kw):
|
208
|
+
"""Handle TEXT type compilation."""
|
209
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
210
|
+
|
211
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
212
|
+
return mysql_compiler.visit_text(type_, **kw)
|
213
|
+
|
214
|
+
def visit_boolean(self, type_, **kw):
|
215
|
+
"""Handle BOOLEAN type compilation."""
|
216
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
217
|
+
|
218
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
219
|
+
return mysql_compiler.visit_boolean(type_, **kw)
|
220
|
+
|
221
|
+
def visit_float(self, type_, **kw):
|
222
|
+
"""Handle FLOAT type compilation."""
|
223
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
224
|
+
|
225
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
226
|
+
return mysql_compiler.visit_float(type_, **kw)
|
227
|
+
|
228
|
+
def visit_numeric(self, type_, **kw):
|
229
|
+
"""Handle NUMERIC type compilation."""
|
230
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
231
|
+
|
232
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
233
|
+
return mysql_compiler.visit_numeric(type_, **kw)
|
234
|
+
|
235
|
+
def visit_DECIMAL(self, type_, **kw):
|
236
|
+
"""Handle DECIMAL type compilation for SQLAlchemy 2.0.x."""
|
237
|
+
if (
|
238
|
+
hasattr(type_, 'precision')
|
239
|
+
and hasattr(type_, 'scale')
|
240
|
+
and type_.precision is not None
|
241
|
+
and type_.scale is not None
|
242
|
+
):
|
243
|
+
return f"DECIMAL({type_.precision}, {type_.scale})"
|
244
|
+
return "DECIMAL"
|
245
|
+
|
246
|
+
def visit_NUMERIC(self, type_, **kw):
|
247
|
+
"""Handle NUMERIC type compilation for SQLAlchemy 2.0.x."""
|
248
|
+
if (
|
249
|
+
hasattr(type_, 'precision')
|
250
|
+
and hasattr(type_, 'scale')
|
251
|
+
and type_.precision is not None
|
252
|
+
and type_.scale is not None
|
253
|
+
):
|
254
|
+
return f"DECIMAL({type_.precision}, {type_.scale})"
|
255
|
+
return "DECIMAL"
|
256
|
+
|
257
|
+
def visit_BIGINT(self, type_, **kw):
|
258
|
+
"""Handle BIGINT type compilation for SQLAlchemy 2.0.x."""
|
259
|
+
return "BIGINT"
|
260
|
+
|
261
|
+
def visit_big_integer(self, type_, **kw):
|
262
|
+
"""Handle BigInteger type compilation for SQLAlchemy 2.0.x."""
|
263
|
+
return "BIGINT"
|
264
|
+
|
265
|
+
def visit_TIMESTAMP(self, type_, **kw):
|
266
|
+
"""Handle TIMESTAMP type compilation for SQLAlchemy 2.0.x."""
|
267
|
+
return "TIMESTAMP"
|
268
|
+
|
269
|
+
def visit_date(self, type_, **kw):
|
270
|
+
"""Handle DATE type compilation."""
|
271
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
272
|
+
|
273
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
274
|
+
return mysql_compiler.visit_date(type_, **kw)
|
275
|
+
|
276
|
+
def visit_datetime(self, type_, **kw):
|
277
|
+
"""Handle DATETIME type compilation."""
|
278
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
279
|
+
|
280
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
281
|
+
return mysql_compiler.visit_datetime(type_, **kw)
|
282
|
+
|
283
|
+
def visit_time(self, type_, **kw):
|
284
|
+
"""Handle TIME type compilation."""
|
285
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
286
|
+
|
287
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
288
|
+
return mysql_compiler.visit_time(type_, **kw)
|
289
|
+
|
290
|
+
def visit_timestamp(self, type_, **kw):
|
291
|
+
"""Handle TIMESTAMP type compilation."""
|
292
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
293
|
+
|
294
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
295
|
+
return mysql_compiler.visit_TIMESTAMP(type_, **kw)
|
296
|
+
|
297
|
+
def visit_type_decorator(self, type_, **kw):
|
298
|
+
"""Handle TypeDecorator type compilation."""
|
299
|
+
# For MatrixOne vector types, handle them directly
|
300
|
+
if hasattr(type_, 'type_engine'):
|
301
|
+
actual_type = type_.type_engine(self.dialect)
|
302
|
+
if hasattr(actual_type, '__visit_name__') and actual_type.__visit_name__ == 'VECTOR':
|
303
|
+
return self.visit_VECTOR(actual_type, **kw)
|
304
|
+
|
305
|
+
# For other types, delegate to MySQL compiler
|
306
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
307
|
+
|
308
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
309
|
+
return mysql_compiler.visit_type_decorator(type_, **kw)
|
310
|
+
|
311
|
+
# Additional type methods for comprehensive SQLAlchemy 2.0.x support
|
312
|
+
def visit_small_integer(self, type_, **kw):
|
313
|
+
"""Handle SMALLINT type compilation."""
|
314
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
315
|
+
|
316
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
317
|
+
return mysql_compiler.visit_small_integer(type_, **kw)
|
318
|
+
|
319
|
+
def visit_CHAR(self, type_, **kw):
|
320
|
+
"""Handle CHAR type compilation."""
|
321
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
322
|
+
|
323
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
324
|
+
return mysql_compiler.visit_CHAR(type_, **kw)
|
325
|
+
|
326
|
+
def visit_VARCHAR(self, type_, **kw):
|
327
|
+
"""Handle VARCHAR type compilation."""
|
328
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
329
|
+
|
330
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
331
|
+
return mysql_compiler.visit_VARCHAR(type_, **kw)
|
332
|
+
|
333
|
+
def visit_unicode(self, type_, **kw):
|
334
|
+
"""Handle Unicode type compilation."""
|
335
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
336
|
+
|
337
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
338
|
+
return mysql_compiler.visit_unicode(type_, **kw)
|
339
|
+
|
340
|
+
def visit_unicode_text(self, type_, **kw):
|
341
|
+
"""Handle UnicodeText type compilation."""
|
342
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
343
|
+
|
344
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
345
|
+
return mysql_compiler.visit_unicode_text(type_, **kw)
|
346
|
+
|
347
|
+
def visit_large_binary(self, type_, **kw):
|
348
|
+
"""Handle LargeBinary type compilation."""
|
349
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
350
|
+
|
351
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
352
|
+
return mysql_compiler.visit_large_binary(type_, **kw)
|
353
|
+
|
354
|
+
def visit_binary(self, type_, **kw):
|
355
|
+
"""Handle Binary type compilation."""
|
356
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
357
|
+
|
358
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
359
|
+
return mysql_compiler.visit_BINARY(type_, **kw)
|
360
|
+
|
361
|
+
def visit_BLOB(self, type_, **kw):
|
362
|
+
"""Handle BLOB type compilation."""
|
363
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
364
|
+
|
365
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
366
|
+
return mysql_compiler.visit_BLOB(type_, **kw)
|
367
|
+
|
368
|
+
def visit_enum(self, type_, **kw):
|
369
|
+
"""Handle Enum type compilation."""
|
370
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
371
|
+
|
372
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
373
|
+
return mysql_compiler.visit_enum(type_, **kw)
|
374
|
+
|
375
|
+
def visit_pickle(self, type_, **kw):
|
376
|
+
"""Handle PickleType compilation."""
|
377
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
378
|
+
|
379
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
380
|
+
return mysql_compiler.visit_pickle(type_, **kw)
|
381
|
+
|
382
|
+
def visit_interval(self, type_, **kw):
|
383
|
+
"""Handle Interval type compilation."""
|
384
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
385
|
+
|
386
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
387
|
+
return mysql_compiler.visit_interval(type_, **kw)
|
388
|
+
|
389
|
+
def visit_uuid(self, type_, **kw):
|
390
|
+
"""Handle UUID type compilation."""
|
391
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
392
|
+
|
393
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
394
|
+
return mysql_compiler.visit_uuid(type_, **kw)
|
395
|
+
|
396
|
+
def visit_JSON(self, type_, **kw):
|
397
|
+
"""Handle JSON type compilation."""
|
398
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
399
|
+
|
400
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
401
|
+
return mysql_compiler.visit_JSON(type_, **kw)
|
402
|
+
|
403
|
+
def visit_arbitrary_type(self, type_, **kw):
|
404
|
+
"""Handle arbitrary type compilation."""
|
405
|
+
from sqlalchemy.dialects.mysql.base import MySQLDialect
|
406
|
+
|
407
|
+
mysql_compiler = MySQLDialect.type_compiler_cls(self.dialect)
|
408
|
+
return mysql_compiler.visit_arbitrary_type(type_, **kw)
|
409
|
+
|
410
|
+
else:
|
411
|
+
# SQLAlchemy 1.4.x
|
412
|
+
class MatrixOneTypeCompiler(MySQLDialect.type_compiler):
|
413
|
+
"""MatrixOne type compiler for handling vector types."""
|
414
|
+
|
415
|
+
def visit_VECTOR(self, type_, **kw):
|
416
|
+
"""Handle VECTOR type compilation."""
|
417
|
+
if hasattr(type_, "get_col_spec"):
|
418
|
+
return type_.get_col_spec()
|
419
|
+
return "VECTOR"
|
420
|
+
|
421
|
+
def visit_timestamp(self, type_, **kw):
|
422
|
+
"""Handle TIMESTAMP type compilation for SQLAlchemy 1.4.x."""
|
423
|
+
# In SQLAlchemy 1.4.x, we need to handle TIMESTAMP differently
|
424
|
+
return "TIMESTAMP"
|
425
|
+
|
426
|
+
def visit_DECIMAL(self, type_, **kw):
|
427
|
+
"""Handle DECIMAL type compilation for SQLAlchemy 2.0.x."""
|
428
|
+
if (
|
429
|
+
hasattr(type_, 'precision')
|
430
|
+
and hasattr(type_, 'scale')
|
431
|
+
and type_.precision is not None
|
432
|
+
and type_.scale is not None
|
433
|
+
):
|
434
|
+
return f"DECIMAL({type_.precision}, {type_.scale})"
|
435
|
+
return "DECIMAL"
|
436
|
+
|
437
|
+
def visit_NUMERIC(self, type_, **kw):
|
438
|
+
"""Handle NUMERIC type compilation for SQLAlchemy 2.0.x."""
|
439
|
+
if (
|
440
|
+
hasattr(type_, 'precision')
|
441
|
+
and hasattr(type_, 'scale')
|
442
|
+
and type_.precision is not None
|
443
|
+
and type_.scale is not None
|
444
|
+
):
|
445
|
+
return f"DECIMAL({type_.precision}, {type_.scale})"
|
446
|
+
return "DECIMAL"
|
447
|
+
|
448
|
+
def visit_BIGINT(self, type_, **kw):
|
449
|
+
"""Handle BIGINT type compilation for SQLAlchemy 1.4.x."""
|
450
|
+
return "BIGINT"
|
451
|
+
|
452
|
+
def visit_big_integer(self, type_, **kw):
|
453
|
+
"""Handle BigInteger type compilation for SQLAlchemy 1.4.x."""
|
454
|
+
return "BIGINT"
|
455
|
+
|
456
|
+
def visit_TIMESTAMP(self, type_, **kw):
|
457
|
+
"""Handle TIMESTAMP type compilation for SQLAlchemy 1.4.x."""
|
458
|
+
return "TIMESTAMP"
|
459
|
+
|
460
|
+
# Additional type methods for comprehensive SQLAlchemy 1.4.x support
|
461
|
+
def visit_small_integer(self, type_, **kw):
|
462
|
+
"""Handle SMALLINT type compilation."""
|
463
|
+
return "SMALLINT"
|
464
|
+
|
465
|
+
def visit_CHAR(self, type_, **kw):
|
466
|
+
"""Handle CHAR type compilation."""
|
467
|
+
if hasattr(type_, 'length') and type_.length:
|
468
|
+
return f"CHAR({type_.length})"
|
469
|
+
return "CHAR"
|
470
|
+
|
471
|
+
def visit_VARCHAR(self, type_, **kw):
|
472
|
+
"""Handle VARCHAR type compilation."""
|
473
|
+
if hasattr(type_, 'length') and type_.length:
|
474
|
+
return f"VARCHAR({type_.length})"
|
475
|
+
return "VARCHAR"
|
476
|
+
|
477
|
+
def visit_unicode(self, type_, **kw):
|
478
|
+
"""Handle Unicode type compilation."""
|
479
|
+
if hasattr(type_, 'length') and type_.length:
|
480
|
+
return f"VARCHAR({type_.length})"
|
481
|
+
return "VARCHAR"
|
482
|
+
|
483
|
+
def visit_unicode_text(self, type_, **kw):
|
484
|
+
"""Handle UnicodeText type compilation."""
|
485
|
+
return "TEXT"
|
486
|
+
|
487
|
+
def visit_large_binary(self, type_, **kw):
|
488
|
+
"""Handle LargeBinary type compilation."""
|
489
|
+
return "BLOB"
|
490
|
+
|
491
|
+
def visit_binary(self, type_, **kw):
|
492
|
+
"""Handle Binary type compilation."""
|
493
|
+
if hasattr(type_, 'length') and type_.length:
|
494
|
+
return f"BINARY({type_.length})"
|
495
|
+
return "BINARY"
|
496
|
+
|
497
|
+
def visit_BLOB(self, type_, **kw):
|
498
|
+
"""Handle BLOB type compilation."""
|
499
|
+
return "BLOB"
|
500
|
+
|
501
|
+
def visit_enum(self, type_, **kw):
|
502
|
+
"""Handle Enum type compilation."""
|
503
|
+
if hasattr(type_, 'enums') and type_.enums:
|
504
|
+
enum_values = "','".join(type_.enums)
|
505
|
+
return f"ENUM('{enum_values}')"
|
506
|
+
return "ENUM"
|
507
|
+
|
508
|
+
def visit_pickle(self, type_, **kw):
|
509
|
+
"""Handle PickleType compilation."""
|
510
|
+
return "BLOB"
|
511
|
+
|
512
|
+
def visit_interval(self, type_, **kw):
|
513
|
+
"""Handle Interval type compilation."""
|
514
|
+
return "DATETIME"
|
515
|
+
|
516
|
+
def visit_uuid(self, type_, **kw):
|
517
|
+
"""Handle UUID type compilation."""
|
518
|
+
return "CHAR(32)"
|
519
|
+
|
520
|
+
def visit_JSON(self, type_, **kw):
|
521
|
+
"""Handle JSON type compilation."""
|
522
|
+
return "JSON"
|
523
|
+
|
524
|
+
def visit_arbitrary_type(self, type_, **kw):
|
525
|
+
"""Handle arbitrary type compilation."""
|
526
|
+
return "VARCHAR"
|
527
|
+
|
528
|
+
|
529
|
+
# Register the dialect
|
530
|
+
MatrixOneDialect.statement_compiler = MatrixOneCompiler
|
531
|
+
MatrixOneDialect.type_compiler = MatrixOneTypeCompiler
|
532
|
+
|
533
|
+
|
534
|
+
# MatrixOneVectorType removed - use VectorType from vector_type.py instead
|