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.
Files changed (122) hide show
  1. matrixone/__init__.py +155 -0
  2. matrixone/account.py +723 -0
  3. matrixone/async_client.py +3913 -0
  4. matrixone/async_metadata_manager.py +311 -0
  5. matrixone/async_orm.py +123 -0
  6. matrixone/async_vector_index_manager.py +633 -0
  7. matrixone/base_client.py +208 -0
  8. matrixone/client.py +4672 -0
  9. matrixone/config.py +452 -0
  10. matrixone/connection_hooks.py +286 -0
  11. matrixone/exceptions.py +89 -0
  12. matrixone/logger.py +782 -0
  13. matrixone/metadata.py +820 -0
  14. matrixone/moctl.py +219 -0
  15. matrixone/orm.py +2277 -0
  16. matrixone/pitr.py +646 -0
  17. matrixone/pubsub.py +771 -0
  18. matrixone/restore.py +411 -0
  19. matrixone/search_vector_index.py +1176 -0
  20. matrixone/snapshot.py +550 -0
  21. matrixone/sql_builder.py +844 -0
  22. matrixone/sqlalchemy_ext/__init__.py +161 -0
  23. matrixone/sqlalchemy_ext/adapters.py +163 -0
  24. matrixone/sqlalchemy_ext/dialect.py +534 -0
  25. matrixone/sqlalchemy_ext/fulltext_index.py +895 -0
  26. matrixone/sqlalchemy_ext/fulltext_search.py +1686 -0
  27. matrixone/sqlalchemy_ext/hnsw_config.py +194 -0
  28. matrixone/sqlalchemy_ext/ivf_config.py +252 -0
  29. matrixone/sqlalchemy_ext/table_builder.py +351 -0
  30. matrixone/sqlalchemy_ext/vector_index.py +1721 -0
  31. matrixone/sqlalchemy_ext/vector_type.py +948 -0
  32. matrixone/version.py +580 -0
  33. matrixone_python_sdk-0.1.0.dist-info/METADATA +706 -0
  34. matrixone_python_sdk-0.1.0.dist-info/RECORD +122 -0
  35. matrixone_python_sdk-0.1.0.dist-info/WHEEL +5 -0
  36. matrixone_python_sdk-0.1.0.dist-info/entry_points.txt +5 -0
  37. matrixone_python_sdk-0.1.0.dist-info/licenses/LICENSE +200 -0
  38. matrixone_python_sdk-0.1.0.dist-info/top_level.txt +2 -0
  39. tests/__init__.py +19 -0
  40. tests/offline/__init__.py +20 -0
  41. tests/offline/conftest.py +77 -0
  42. tests/offline/test_account.py +703 -0
  43. tests/offline/test_async_client_query_comprehensive.py +1218 -0
  44. tests/offline/test_basic.py +54 -0
  45. tests/offline/test_case_sensitivity.py +227 -0
  46. tests/offline/test_connection_hooks_offline.py +287 -0
  47. tests/offline/test_dialect_schema_handling.py +609 -0
  48. tests/offline/test_explain_methods.py +346 -0
  49. tests/offline/test_filter_logical_in.py +237 -0
  50. tests/offline/test_fulltext_search_comprehensive.py +795 -0
  51. tests/offline/test_ivf_config.py +249 -0
  52. tests/offline/test_join_methods.py +281 -0
  53. tests/offline/test_join_sqlalchemy_compatibility.py +276 -0
  54. tests/offline/test_logical_in_method.py +237 -0
  55. tests/offline/test_matrixone_version_parsing.py +264 -0
  56. tests/offline/test_metadata_offline.py +557 -0
  57. tests/offline/test_moctl.py +300 -0
  58. tests/offline/test_moctl_simple.py +251 -0
  59. tests/offline/test_model_support_offline.py +359 -0
  60. tests/offline/test_model_support_simple.py +225 -0
  61. tests/offline/test_pinecone_filter_offline.py +377 -0
  62. tests/offline/test_pitr.py +585 -0
  63. tests/offline/test_pubsub.py +712 -0
  64. tests/offline/test_query_update.py +283 -0
  65. tests/offline/test_restore.py +445 -0
  66. tests/offline/test_snapshot_comprehensive.py +384 -0
  67. tests/offline/test_sql_escaping_edge_cases.py +551 -0
  68. tests/offline/test_sqlalchemy_integration.py +382 -0
  69. tests/offline/test_sqlalchemy_vector_integration.py +434 -0
  70. tests/offline/test_table_builder.py +198 -0
  71. tests/offline/test_unified_filter.py +398 -0
  72. tests/offline/test_unified_transaction.py +495 -0
  73. tests/offline/test_vector_index.py +238 -0
  74. tests/offline/test_vector_operations.py +688 -0
  75. tests/offline/test_vector_type.py +174 -0
  76. tests/offline/test_version_core.py +328 -0
  77. tests/offline/test_version_management.py +372 -0
  78. tests/offline/test_version_standalone.py +652 -0
  79. tests/online/__init__.py +20 -0
  80. tests/online/conftest.py +216 -0
  81. tests/online/test_account_management.py +194 -0
  82. tests/online/test_advanced_features.py +344 -0
  83. tests/online/test_async_client_interfaces.py +330 -0
  84. tests/online/test_async_client_online.py +285 -0
  85. tests/online/test_async_model_insert_online.py +293 -0
  86. tests/online/test_async_orm_online.py +300 -0
  87. tests/online/test_async_simple_query_online.py +802 -0
  88. tests/online/test_async_transaction_simple_query.py +300 -0
  89. tests/online/test_basic_connection.py +130 -0
  90. tests/online/test_client_online.py +238 -0
  91. tests/online/test_config.py +90 -0
  92. tests/online/test_config_validation.py +123 -0
  93. tests/online/test_connection_hooks_new_online.py +217 -0
  94. tests/online/test_dialect_schema_handling_online.py +331 -0
  95. tests/online/test_filter_logical_in_online.py +374 -0
  96. tests/online/test_fulltext_comprehensive.py +1773 -0
  97. tests/online/test_fulltext_label_online.py +433 -0
  98. tests/online/test_fulltext_search_online.py +842 -0
  99. tests/online/test_ivf_stats_online.py +506 -0
  100. tests/online/test_logger_integration.py +311 -0
  101. tests/online/test_matrixone_query_orm.py +540 -0
  102. tests/online/test_metadata_online.py +579 -0
  103. tests/online/test_model_insert_online.py +255 -0
  104. tests/online/test_mysql_driver_validation.py +213 -0
  105. tests/online/test_orm_advanced_features.py +2022 -0
  106. tests/online/test_orm_cte_integration.py +269 -0
  107. tests/online/test_orm_online.py +270 -0
  108. tests/online/test_pinecone_filter.py +708 -0
  109. tests/online/test_pubsub_operations.py +352 -0
  110. tests/online/test_query_methods.py +225 -0
  111. tests/online/test_query_update_online.py +433 -0
  112. tests/online/test_search_vector_index.py +557 -0
  113. tests/online/test_simple_fulltext_online.py +915 -0
  114. tests/online/test_snapshot_comprehensive.py +998 -0
  115. tests/online/test_sqlalchemy_engine_integration.py +336 -0
  116. tests/online/test_sqlalchemy_integration.py +425 -0
  117. tests/online/test_transaction_contexts.py +1219 -0
  118. tests/online/test_transaction_insert_methods.py +356 -0
  119. tests/online/test_transaction_query_methods.py +288 -0
  120. tests/online/test_unified_filter_online.py +529 -0
  121. tests/online/test_vector_comprehensive.py +706 -0
  122. 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