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,283 @@
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
+ Offline tests for query update functionality
17
+ """
18
+
19
+ import pytest
20
+ import os
21
+ import sys
22
+ from unittest.mock import Mock, MagicMock
23
+
24
+ # Add the matrixone package to the path
25
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
26
+
27
+ from matrixone.orm import BaseMatrixOneQuery, MatrixOneQuery
28
+ from sqlalchemy import func
29
+
30
+
31
+ class MockUser:
32
+ """Mock SQLAlchemy model for testing"""
33
+
34
+ __tablename__ = "users"
35
+ __name__ = "MockUser" # Add __name__ attribute
36
+
37
+ def __init__(self):
38
+ self.id = Mock()
39
+ self.name = Mock()
40
+ self.email = Mock()
41
+ self.age = Mock()
42
+ self.login_count = Mock()
43
+ self.last_login = Mock()
44
+ self.status = Mock()
45
+
46
+
47
+ class TestQueryUpdate:
48
+ """Test query update functionality"""
49
+
50
+ def setup_method(self):
51
+ """Set up test fixtures"""
52
+ self.mock_client = Mock()
53
+ self.mock_client.execute.return_value = Mock()
54
+ self.mock_client.execute.return_value.rows = []
55
+
56
+ # Create mock user model
57
+ self.user_model = MockUser()
58
+
59
+ # Create query instances
60
+ self.base_query = BaseMatrixOneQuery(self.user_model, self.mock_client)
61
+ self.matrixone_query = MatrixOneQuery(self.user_model, self.mock_client)
62
+
63
+ def test_simple_update(self):
64
+ """Test simple update with key-value pairs"""
65
+ query = self.base_query.update(name="New Name", email="new@example.com")
66
+
67
+ # Check that query type is set to UPDATE
68
+ assert query._query_type == "UPDATE"
69
+
70
+ # Check that update columns are set correctly
71
+ assert "name = ?" in query._update_set_columns
72
+ assert "email = ?" in query._update_set_columns
73
+
74
+ # Check that update values are set correctly
75
+ assert "New Name" in query._update_set_values
76
+ assert "new@example.com" in query._update_set_values
77
+
78
+ def test_update_with_filter(self):
79
+ """Test update with filter conditions"""
80
+ query = self.base_query.update(status="inactive").filter("age > ?", 65)
81
+
82
+ # Check that query type is set to UPDATE
83
+ assert query._query_type == "UPDATE"
84
+
85
+ # Check that update columns are set
86
+ assert "status = ?" in query._update_set_columns
87
+ assert "inactive" in query._update_set_values
88
+
89
+ # Check that filter conditions are set
90
+ assert "age > 65" in query._where_conditions
91
+
92
+ def test_update_with_sqlalchemy_expressions(self):
93
+ """Test update with SQLAlchemy expressions"""
94
+ # Mock SQLAlchemy expression
95
+ mock_expression = Mock()
96
+ mock_expression.compile.return_value = Mock()
97
+ mock_expression.compile.return_value.__str__ = Mock(return_value="NOW()")
98
+
99
+ query = self.base_query.update(last_login=mock_expression)
100
+
101
+ # Check that query type is set to UPDATE
102
+ assert query._query_type == "UPDATE"
103
+
104
+ # Check that SQLAlchemy expression is handled correctly
105
+ assert "last_login = NOW()" in query._update_set_columns
106
+
107
+ def test_update_with_complex_expressions(self):
108
+ """Test update with complex SQLAlchemy expressions"""
109
+ # Mock complex expression
110
+ mock_expression = Mock()
111
+ mock_expression.compile.return_value = Mock()
112
+ mock_expression.compile.return_value.__str__ = Mock(return_value="login_count + 1")
113
+
114
+ query = self.base_query.update(login_count=mock_expression)
115
+
116
+ # Check that query type is set to UPDATE
117
+ assert query._query_type == "UPDATE"
118
+
119
+ # Check that complex expression is handled correctly
120
+ assert "login_count = login_count + 1" in query._update_set_columns
121
+
122
+ def test_update_build_sql_simple(self):
123
+ """Test building UPDATE SQL with simple values"""
124
+ query = self.base_query.update(name="New Name", email="new@example.com").filter("id = ?", 1)
125
+
126
+ sql, params = query._build_update_sql()
127
+
128
+ # Check SQL structure
129
+ assert "UPDATE mockuser SET" in sql
130
+ assert "name = ?" in sql
131
+ assert "email = ?" in sql
132
+ assert "WHERE id = 1" in sql
133
+
134
+ # Check parameters
135
+ assert "New Name" in params
136
+ assert "new@example.com" in params
137
+
138
+ def test_update_build_sql_with_expressions(self):
139
+ """Test building UPDATE SQL with SQLAlchemy expressions"""
140
+ # Mock SQLAlchemy expression
141
+ mock_expression = Mock()
142
+ mock_compiled = Mock()
143
+ mock_compiled.__str__ = Mock(return_value="NOW()")
144
+ mock_expression.compile.return_value = mock_compiled
145
+
146
+ query = self.base_query.update(last_login=mock_expression, status="active").filter("id = ?", 1)
147
+
148
+ sql, params = query._build_update_sql()
149
+
150
+ # Check SQL structure
151
+ assert "UPDATE mockuser SET" in sql
152
+ assert "last_login = NOW()" in sql
153
+ assert "status = ?" in sql
154
+ assert "WHERE id = 1" in sql
155
+
156
+ # Check parameters
157
+ assert "active" in params
158
+
159
+ def test_update_execute(self):
160
+ """Test executing UPDATE query"""
161
+ query = self.base_query.update(name="New Name").filter("id = ?", 1)
162
+
163
+ # Mock the _execute method
164
+ query._execute = Mock(return_value=Mock())
165
+
166
+ # Use MatrixOneQuery which has execute method
167
+ matrixone_query = MatrixOneQuery(self.user_model, self.mock_client)
168
+ matrixone_query._query_type = "UPDATE"
169
+ matrixone_query._update_set_columns = ["name = ?"]
170
+ matrixone_query._update_set_values = ["New Name"]
171
+ matrixone_query._where_conditions = ["id = 1"]
172
+ matrixone_query._where_params = []
173
+ matrixone_query._table_name = "mockuser"
174
+ matrixone_query._execute = Mock(return_value=Mock())
175
+
176
+ result = matrixone_query.execute()
177
+
178
+ # Check that _execute was called
179
+ matrixone_query._execute.assert_called_once()
180
+
181
+ # Check that _build_update_sql was called
182
+ sql, params = matrixone_query._execute.call_args[0]
183
+ assert "UPDATE mockuser SET" in sql
184
+ assert "name = ?" in sql
185
+ assert "WHERE id = 1" in sql
186
+
187
+ def test_update_no_set_clauses_error(self):
188
+ """Test that ValueError is raised when no SET clauses are provided"""
189
+ query = self.base_query.filter("id = ?", 1)
190
+
191
+ with pytest.raises(ValueError, match="No SET clauses provided for UPDATE"):
192
+ query._build_update_sql()
193
+
194
+ def test_update_with_multiple_filters(self):
195
+ """Test update with multiple filter conditions"""
196
+ query = self.base_query.update(status="inactive").filter("age > ?", 65).filter("last_login < ?", "2023-01-01")
197
+
198
+ # Check that query type is set to UPDATE
199
+ assert query._query_type == "UPDATE"
200
+
201
+ # Check that update columns are set
202
+ assert "status = ?" in query._update_set_columns
203
+ assert "inactive" in query._update_set_values
204
+
205
+ # Check that multiple filter conditions are set
206
+ assert "age > 65" in query._where_conditions
207
+ assert "last_login < '2023-01-01'" in query._where_conditions
208
+
209
+ def test_update_with_sqlalchemy_quoted_columns(self):
210
+ """Test update with SQLAlchemy quoted column names"""
211
+ # Mock SQLAlchemy expression with quoted columns
212
+ mock_expression = Mock()
213
+ mock_expression.compile.return_value = Mock()
214
+ mock_expression.compile.return_value.__str__ = Mock(return_value="COUNT('id')")
215
+
216
+ query = self.base_query.update(user_count=mock_expression)
217
+
218
+ # Check that quoted columns are fixed
219
+ assert "user_count = COUNT(id)" in query._update_set_columns
220
+
221
+ def test_matrixone_query_update(self):
222
+ """Test MatrixOneQuery update functionality"""
223
+ query = self.matrixone_query.update(name="New Name", email="new@example.com").filter("id = ?", 1)
224
+
225
+ # Check that query type is set to UPDATE
226
+ assert query._query_type == "UPDATE"
227
+
228
+ # Check that update columns are set correctly
229
+ assert "name = ?" in query._update_set_columns
230
+ assert "email = ?" in query._update_set_columns
231
+
232
+ # Check that update values are set correctly
233
+ assert "New Name" in query._update_set_values
234
+ assert "new@example.com" in query._update_set_values
235
+
236
+ def test_update_method_chaining(self):
237
+ """Test that update method returns self for chaining"""
238
+ query = self.base_query.update(name="New Name")
239
+
240
+ # Check that the same instance is returned
241
+ assert query is self.base_query
242
+
243
+ # Check that chaining works
244
+ chained_query = query.filter("id = ?", 1).filter("status = ?", "active")
245
+
246
+ assert chained_query is self.base_query
247
+ assert query._query_type == "UPDATE"
248
+ assert "id = 1" in query._where_conditions
249
+ assert "status = 'active'" in query._where_conditions
250
+
251
+ def test_update_with_none_values(self):
252
+ """Test update with None values"""
253
+ query = self.base_query.update(name=None, email="new@example.com")
254
+
255
+ # Check that None values are handled correctly
256
+ assert "name = ?" in query._update_set_columns
257
+ assert "email = ?" in query._update_set_columns
258
+ assert None in query._update_set_values
259
+ assert "new@example.com" in query._update_set_values
260
+
261
+ def test_update_with_numeric_values(self):
262
+ """Test update with numeric values"""
263
+ query = self.base_query.update(age=25, salary=50000.50)
264
+
265
+ # Check that numeric values are handled correctly
266
+ assert "age = ?" in query._update_set_columns
267
+ assert "salary = ?" in query._update_set_columns
268
+ assert 25 in query._update_set_values
269
+ assert 50000.50 in query._update_set_values
270
+
271
+ def test_update_with_boolean_values(self):
272
+ """Test update with boolean values"""
273
+ query = self.base_query.update(active=True, verified=False)
274
+
275
+ # Check that boolean values are handled correctly
276
+ assert "active = ?" in query._update_set_columns
277
+ assert "verified = ?" in query._update_set_columns
278
+ assert True in query._update_set_values
279
+ assert False in query._update_set_values
280
+
281
+
282
+ if __name__ == "__main__":
283
+ pytest.main([__file__])