pyseekdb 0.1.0.dev3__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.
@@ -0,0 +1,652 @@
1
+ """
2
+ Collection DML tests - testing collection.add(), collection.delete(), collection.upsert(), collection.update() interfaces for all three modes
3
+ Supports configuring connection parameters via environment variables
4
+ """
5
+ import pytest
6
+ import sys
7
+ import os
8
+ import time
9
+ import uuid
10
+ from pathlib import Path
11
+
12
+ # Add project path
13
+ project_root = Path(__file__).parent.parent.parent
14
+ sys.path.insert(0, str(project_root))
15
+
16
+ import seekdbclient
17
+ from seekdbclient.client.meta_info import CollectionNames, CollectionFieldNames
18
+
19
+
20
+ # ==================== Environment Variable Configuration ====================
21
+ # Embedded mode
22
+ SEEKDB_PATH = os.environ.get('SEEKDB_PATH', os.path.join(project_root, "seekdb_store"))
23
+ SEEKDB_DATABASE = os.environ.get('SEEKDB_DATABASE', 'test')
24
+
25
+ # Server mode
26
+ SERVER_HOST = os.environ.get('SERVER_HOST', 'localhost')
27
+ SERVER_PORT = int(os.environ.get('SERVER_PORT', '2881'))
28
+ SERVER_DATABASE = os.environ.get('SERVER_DATABASE', 'test')
29
+ SERVER_USER = os.environ.get('SERVER_USER', 'root')
30
+ SERVER_PASSWORD = os.environ.get('SERVER_PASSWORD', '')
31
+
32
+ # OceanBase mode
33
+ OB_HOST = os.environ.get('OB_HOST', 'localhost')
34
+ OB_PORT = int(os.environ.get('OB_PORT', '11202'))
35
+ OB_TENANT = os.environ.get('OB_TENANT', 'mysql')
36
+ OB_DATABASE = os.environ.get('OB_DATABASE', 'test')
37
+ OB_USER = os.environ.get('OB_USER', 'root')
38
+ OB_PASSWORD = os.environ.get('OB_PASSWORD', '')
39
+
40
+
41
+ class TestCollectionDML:
42
+ """Test collection DML operations (add, delete, upsert, update) for all three modes"""
43
+
44
+ def test_embedded_collection_dml(self):
45
+ """Test collection DML operations with embedded client"""
46
+ if not os.path.exists(SEEKDB_PATH):
47
+ pytest.skip(
48
+ f"SeekDB data directory does not exist: {SEEKDB_PATH}\n"
49
+ f"Set SEEKDB_PATH environment variable to run this test"
50
+ )
51
+
52
+ # Check if seekdb package is available
53
+ try:
54
+ import seekdb
55
+ except ImportError:
56
+ pytest.skip("SeekDB embedded package is not installed")
57
+
58
+ # Create embedded client
59
+ client = seekdbclient.Client(
60
+ path=SEEKDB_PATH,
61
+ database=SEEKDB_DATABASE
62
+ )
63
+
64
+ assert client is not None
65
+ assert hasattr(client, '_server')
66
+ assert isinstance(client._server, seekdbclient.SeekdbEmbeddedClient)
67
+
68
+ # Create test collection using execute
69
+ collection_name = f"test_dml_{int(time.time())}"
70
+ table_name = CollectionNames.table_name(collection_name)
71
+ dimension = 3
72
+
73
+ # Create table using execute
74
+ create_table_sql = f"""CREATE TABLE `{table_name}` (
75
+ {CollectionFieldNames.ID} varbinary(512) PRIMARY KEY NOT NULL,
76
+ {CollectionFieldNames.DOCUMENT} string,
77
+ {CollectionFieldNames.EMBEDDING} vector({dimension}),
78
+ {CollectionFieldNames.METADATA} json,
79
+ FULLTEXT INDEX idx1({CollectionFieldNames.DOCUMENT}),
80
+ VECTOR INDEX idx2 ({CollectionFieldNames.EMBEDDING}) with(distance=l2, type=hnsw, lib=vsag)
81
+ ) ORGANIZATION = HEAP;"""
82
+ client._server.execute(create_table_sql)
83
+
84
+ # Get collection object
85
+ collection = client.get_collection(name=collection_name)
86
+
87
+ try:
88
+ # Test 1: collection.add - Add single item
89
+ print(f"\n✅ Testing collection.add() - single item for embedded client")
90
+ test_id_1 = str(uuid.uuid4())
91
+ collection.add(
92
+ ids=test_id_1,
93
+ vectors=[1.0, 2.0, 3.0],
94
+ documents="This is test document 1",
95
+ metadatas={"category": "test", "score": 100}
96
+ )
97
+
98
+ # Verify using collection.get
99
+ results = collection.get(ids=test_id_1)
100
+ assert len(results) == 1
101
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
102
+ assert result_dict.get(CollectionFieldNames.ID) == test_id_1
103
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "This is test document 1"
104
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('category') == "test"
105
+ print(f" Successfully added and verified item with ID: {test_id_1}")
106
+
107
+ # Test 2: collection.add - Add multiple items
108
+ print(f"✅ Testing collection.add() - multiple items")
109
+ test_ids = [str(uuid.uuid4()), str(uuid.uuid4()), str(uuid.uuid4())]
110
+ collection.add(
111
+ ids=test_ids,
112
+ vectors=[[2.0, 3.0, 4.0], [3.0, 4.0, 5.0], [4.0, 5.0, 6.0]],
113
+ documents=["Document 2", "Document 3", "Document 4"],
114
+ metadatas=[
115
+ {"category": "test", "score": 90},
116
+ {"category": "test", "score": 85},
117
+ {"category": "demo", "score": 80}
118
+ ]
119
+ )
120
+
121
+ # Verify using collection.get
122
+ results = collection.get(ids=test_ids)
123
+ assert len(results) == 3
124
+ print(f" Successfully added and verified {len(results)} items")
125
+
126
+ # Test 3: collection.update - Update existing item
127
+ print(f"✅ Testing collection.update() - update existing item")
128
+ collection.update(
129
+ ids=test_id_1,
130
+ documents="Updated document 1",
131
+ metadatas={"category": "test", "score": 95, "updated": True}
132
+ )
133
+
134
+ # Verify update using collection.get
135
+ results = collection.get(ids=test_id_1)
136
+ assert len(results) == 1
137
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
138
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "Updated document 1"
139
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('score') == 95
140
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('updated') is True
141
+ print(f" Successfully updated and verified item with ID: {test_id_1}")
142
+
143
+ # Test 4: collection.upsert - Upsert existing item (should update)
144
+ print(f"✅ Testing collection.upsert() - upsert existing item (update)")
145
+ collection.upsert(
146
+ ids=test_id_1,
147
+ documents="Upserted document 1",
148
+ metadatas={"category": "test", "score": 98}
149
+ )
150
+
151
+ # Verify upsert using collection.get
152
+ results = collection.get(ids=test_id_1)
153
+ assert len(results) == 1
154
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
155
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "Upserted document 1"
156
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('score') == 98
157
+ print(f" Successfully upserted (update) and verified item with ID: {test_id_1}")
158
+
159
+ # Test 5: collection.upsert - Upsert new item (should insert)
160
+ print(f"✅ Testing collection.upsert() - upsert new item (insert)")
161
+ test_id_new = str(uuid.uuid4())
162
+ collection.upsert(
163
+ ids=test_id_new,
164
+ vectors=[5.0, 6.0, 7.0],
165
+ documents="New upserted document",
166
+ metadatas={"category": "new", "score": 99}
167
+ )
168
+
169
+ # Verify upsert using collection.get
170
+ results = collection.get(ids=test_id_new)
171
+ assert len(results) == 1
172
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
173
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "New upserted document"
174
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('category') == "new"
175
+ print(f" Successfully upserted (insert) and verified item with ID: {test_id_new}")
176
+
177
+ # Test 6: collection.delete - Delete by ID
178
+ print(f"✅ Testing collection.delete() - delete by ID")
179
+ # Delete one of the test items
180
+ collection.delete(ids=test_ids[0])
181
+
182
+ # Verify deletion using collection.get
183
+ results = collection.get(ids=test_ids[0])
184
+ assert len(results) == 0
185
+ print(f" Successfully deleted item with ID: {test_ids[0]}")
186
+
187
+ # Verify other items still exist
188
+ results = collection.get(ids=test_ids[1:])
189
+ assert len(results) == 2
190
+ print(f" Verified other items still exist")
191
+
192
+ # Test 7: collection.delete - Delete by metadata filter
193
+ print(f"✅ Testing collection.delete() - delete by metadata filter")
194
+ # Delete items with category="demo"
195
+ collection.delete(where={"category": {"$eq": "demo"}})
196
+
197
+ # Verify deletion using collection.get
198
+ results = collection.get(where={"category": {"$eq": "demo"}})
199
+ assert len(results) == 0
200
+ print(f" Successfully deleted items with category='demo'")
201
+
202
+ # Test 8: Verify final state using collection.get
203
+ print(f"✅ Testing final state verification")
204
+ all_results = collection.get(limit=100)
205
+ print(f" Final collection count: {len(all_results)} items")
206
+ assert len(all_results) > 0
207
+
208
+ finally:
209
+ # Cleanup
210
+ try:
211
+ client.delete_collection(name=collection_name)
212
+ print(f" Cleaned up collection: {collection_name}")
213
+ except Exception as cleanup_error:
214
+ print(f" Warning: Failed to cleanup collection: {cleanup_error}")
215
+
216
+ def test_server_collection_dml(self):
217
+ """Test collection DML operations with server client"""
218
+ # Create server client
219
+ client = seekdbclient.Client(
220
+ host=SERVER_HOST,
221
+ port=SERVER_PORT,
222
+ database=SERVER_DATABASE,
223
+ user=SERVER_USER,
224
+ password=SERVER_PASSWORD
225
+ )
226
+
227
+ assert client is not None
228
+ assert hasattr(client, '_server')
229
+ assert isinstance(client._server, seekdbclient.SeekdbServerClient)
230
+
231
+ # Test connection
232
+ try:
233
+ result = client._server.execute("SELECT 1 as test")
234
+ assert result is not None
235
+ except Exception as e:
236
+ pytest.skip(f"Server connection failed ({SERVER_HOST}:{SERVER_PORT}): {e}")
237
+
238
+ # Create test collection using execute
239
+ collection_name = f"test_dml_{int(time.time())}"
240
+ table_name = CollectionNames.table_name(collection_name)
241
+ dimension = 3
242
+
243
+ # Create table using execute
244
+ create_table_sql = f"""CREATE TABLE `{table_name}` (
245
+ {CollectionFieldNames.ID} varbinary(512) PRIMARY KEY NOT NULL,
246
+ {CollectionFieldNames.DOCUMENT} string,
247
+ {CollectionFieldNames.EMBEDDING} vector({dimension}),
248
+ {CollectionFieldNames.METADATA} json,
249
+ FULLTEXT INDEX idx1({CollectionFieldNames.DOCUMENT}),
250
+ VECTOR INDEX idx2 ({CollectionFieldNames.EMBEDDING}) with(distance=l2, type=hnsw, lib=vsag)
251
+ ) ORGANIZATION = HEAP;"""
252
+ client._server.execute(create_table_sql)
253
+
254
+ # Get collection object
255
+ collection = client.get_collection(name=collection_name)
256
+
257
+ try:
258
+ # Test 1: collection.add - Add single item
259
+ print(f"\n✅ Testing collection.add() - single item for server client")
260
+ test_id_1 = str(uuid.uuid4())
261
+ collection.add(
262
+ ids=test_id_1,
263
+ vectors=[1.0, 2.0, 3.0],
264
+ documents="This is test document 1",
265
+ metadatas={"category": "test", "score": 100}
266
+ )
267
+
268
+ # Verify using collection.get
269
+ results = collection.get(ids=test_id_1)
270
+ assert len(results) == 1
271
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
272
+ assert result_dict.get(CollectionFieldNames.ID) == test_id_1
273
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "This is test document 1"
274
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('category') == "test"
275
+ print(f" Successfully added and verified item with ID: {test_id_1}")
276
+
277
+ # Test 2: collection.add - Add multiple items
278
+ print(f"✅ Testing collection.add() - multiple items")
279
+ test_ids = [str(uuid.uuid4()), str(uuid.uuid4()), str(uuid.uuid4())]
280
+ collection.add(
281
+ ids=test_ids,
282
+ vectors=[[2.0, 3.0, 4.0], [3.0, 4.0, 5.0], [4.0, 5.0, 6.0]],
283
+ documents=["Document 2", "Document 3", "Document 4"],
284
+ metadatas=[
285
+ {"category": "test", "score": 90},
286
+ {"category": "test", "score": 85},
287
+ {"category": "demo", "score": 80}
288
+ ]
289
+ )
290
+
291
+ # Verify using collection.get
292
+ results = collection.get(ids=test_ids)
293
+ assert len(results) == 3
294
+ print(f" Successfully added and verified {len(results)} items")
295
+
296
+ # Test 3: collection.update - Update existing item
297
+ print(f"✅ Testing collection.update() - update existing item")
298
+ collection.update(
299
+ ids=test_id_1,
300
+ documents="Updated document 1",
301
+ metadatas={"category": "test", "score": 95, "updated": True}
302
+ )
303
+
304
+ # Verify update using collection.get
305
+ results = collection.get(ids=test_id_1)
306
+ assert len(results) == 1
307
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
308
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "Updated document 1"
309
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('score') == 95
310
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('updated') is True
311
+ print(f" Successfully updated and verified item with ID: {test_id_1}")
312
+
313
+ # Test 4: collection.update - Update multiple items
314
+ print(f"✅ Testing collection.update() - update multiple items")
315
+ collection.update(
316
+ ids=test_ids[:2],
317
+ vectors=[[2.1, 3.1, 4.1], [3.1, 4.1, 5.1]],
318
+ metadatas=[
319
+ {"category": "test", "score": 92},
320
+ {"category": "test", "score": 87}
321
+ ]
322
+ )
323
+
324
+ # Verify update using collection.get
325
+ results = collection.get(ids=test_ids[:2])
326
+ assert len(results) == 2
327
+ print(f" Successfully updated and verified {len(results)} items")
328
+
329
+ # Test 5: collection.upsert - Upsert existing item (should update)
330
+ print(f"✅ Testing collection.upsert() - upsert existing item (update)")
331
+ collection.upsert(
332
+ ids=test_id_1,
333
+ documents="Upserted document 1",
334
+ metadatas={"category": "test", "score": 98}
335
+ )
336
+
337
+ # Verify upsert using collection.get
338
+ results = collection.get(ids=test_id_1)
339
+ assert len(results) == 1
340
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
341
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "Upserted document 1"
342
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('score') == 98
343
+ print(f" Successfully upserted (update) and verified item with ID: {test_id_1}")
344
+
345
+ # Test 6: collection.upsert - Upsert new item (should insert)
346
+ print(f"✅ Testing collection.upsert() - upsert new item (insert)")
347
+ test_id_new = str(uuid.uuid4())
348
+ collection.upsert(
349
+ ids=test_id_new,
350
+ vectors=[5.0, 6.0, 7.0],
351
+ documents="New upserted document",
352
+ metadatas={"category": "new", "score": 99}
353
+ )
354
+
355
+ # Verify upsert using collection.get
356
+ results = collection.get(ids=test_id_new)
357
+ assert len(results) == 1
358
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
359
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "New upserted document"
360
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('category') == "new"
361
+ print(f" Successfully upserted (insert) and verified item with ID: {test_id_new}")
362
+
363
+ # Test 7: collection.delete - Delete by ID
364
+ print(f"✅ Testing collection.delete() - delete by ID")
365
+ # Delete one of the test items
366
+ collection.delete(ids=test_ids[0])
367
+
368
+ # Verify deletion using collection.get
369
+ results = collection.get(ids=test_ids[0])
370
+ assert len(results) == 0
371
+ print(f" Successfully deleted item with ID: {test_ids[0]}")
372
+
373
+ # Verify other items still exist
374
+ results = collection.get(ids=test_ids[1:])
375
+ assert len(results) == 2
376
+ print(f" Verified other items still exist")
377
+
378
+ # Test 8: collection.delete - Delete by metadata filter
379
+ print(f"✅ Testing collection.delete() - delete by metadata filter")
380
+ # Delete items with category="demo"
381
+ collection.delete(where={"category": {"$eq": "demo"}})
382
+
383
+ # Verify deletion using collection.get
384
+ results = collection.get(where={"category": {"$eq": "demo"}})
385
+ assert len(results) == 0
386
+ print(f" Successfully deleted items with category='demo'")
387
+
388
+ # Test 9: collection.delete - Delete by document filter
389
+ print(f"✅ Testing collection.delete() - delete by document filter")
390
+ # Add an item with specific document content
391
+ test_id_doc = str(uuid.uuid4())
392
+ collection.add(
393
+ ids=test_id_doc,
394
+ vectors=[6.0, 7.0, 8.0],
395
+ documents="Delete this document",
396
+ metadatas={"category": "temp"}
397
+ )
398
+
399
+ # Delete by document filter
400
+ collection.delete(where_document={"$contains": "Delete this"})
401
+
402
+ # Verify deletion using collection.get
403
+ results = collection.get(where_document={"$contains": "Delete this"})
404
+ assert len(results) == 0
405
+ print(f" Successfully deleted items by document filter")
406
+
407
+ # Test 10: Verify final state using collection.get
408
+ print(f"✅ Testing final state verification")
409
+ all_results = collection.get(limit=100)
410
+ print(f" Final collection count: {len(all_results)} items")
411
+ assert len(all_results) > 0
412
+
413
+ finally:
414
+ # Cleanup
415
+ try:
416
+ client.delete_collection(name=collection_name)
417
+ print(f" Cleaned up collection: {collection_name}")
418
+ except Exception as cleanup_error:
419
+ print(f" Warning: Failed to cleanup collection: {cleanup_error}")
420
+
421
+ def test_oceanbase_collection_dml(self):
422
+ """Test collection DML operations with OceanBase client"""
423
+ # Create OceanBase client
424
+ client = seekdbclient.OBClient(
425
+ host=OB_HOST,
426
+ port=OB_PORT,
427
+ tenant=OB_TENANT,
428
+ database=OB_DATABASE,
429
+ user=OB_USER,
430
+ password=OB_PASSWORD
431
+ )
432
+
433
+ assert client is not None
434
+ assert hasattr(client, '_server')
435
+ assert isinstance(client._server, seekdbclient.OceanBaseServerClient)
436
+
437
+ # Test connection
438
+ try:
439
+ result = client._server.execute("SELECT 1 as test")
440
+ assert result is not None
441
+ except Exception as e:
442
+ pytest.skip(f"OceanBase connection failed ({OB_HOST}:{OB_PORT}): {e}")
443
+
444
+ # Create test collection using execute
445
+ collection_name = f"test_dml_{int(time.time())}"
446
+ table_name = CollectionNames.table_name(collection_name)
447
+ dimension = 3
448
+
449
+ # Create table using execute
450
+ create_table_sql = f"""CREATE TABLE `{table_name}` (
451
+ {CollectionFieldNames.ID} varbinary(512) PRIMARY KEY NOT NULL,
452
+ {CollectionFieldNames.DOCUMENT} string,
453
+ {CollectionFieldNames.EMBEDDING} vector({dimension}),
454
+ {CollectionFieldNames.METADATA} json,
455
+ FULLTEXT INDEX idx1({CollectionFieldNames.DOCUMENT}),
456
+ VECTOR INDEX idx2 ({CollectionFieldNames.EMBEDDING}) with(distance=l2, type=hnsw, lib=vsag)
457
+ ) ORGANIZATION = HEAP;"""
458
+ client._server.execute(create_table_sql)
459
+
460
+ # Get collection object
461
+ collection = client.get_collection(name=collection_name)
462
+
463
+ try:
464
+ # Test 1: collection.add - Add single item
465
+ print(f"\n✅ Testing collection.add() - single item for OceanBase client")
466
+ test_id_1 = str(uuid.uuid4())
467
+ collection.add(
468
+ ids=test_id_1,
469
+ vectors=[1.0, 2.0, 3.0],
470
+ documents="This is test document 1",
471
+ metadatas={"category": "test", "score": 100}
472
+ )
473
+
474
+ # Verify using collection.get
475
+ results = collection.get(ids=test_id_1)
476
+ assert len(results) == 1
477
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
478
+ assert result_dict.get(CollectionFieldNames.ID) == test_id_1
479
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "This is test document 1"
480
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('category') == "test"
481
+ print(f" Successfully added and verified item with ID: {test_id_1}")
482
+
483
+ # Test 2: collection.add - Add multiple items
484
+ print(f"✅ Testing collection.add() - multiple items")
485
+ test_ids = [str(uuid.uuid4()), str(uuid.uuid4()), str(uuid.uuid4())]
486
+ collection.add(
487
+ ids=test_ids,
488
+ vectors=[[2.0, 3.0, 4.0], [3.0, 4.0, 5.0], [4.0, 5.0, 6.0]],
489
+ documents=["Document 2", "Document 3", "Document 4"],
490
+ metadatas=[
491
+ {"category": "test", "score": 90},
492
+ {"category": "test", "score": 85},
493
+ {"category": "demo", "score": 80}
494
+ ]
495
+ )
496
+
497
+ # Verify using collection.get
498
+ results = collection.get(ids=test_ids)
499
+ assert len(results) == 3
500
+ print(f" Successfully added and verified {len(results)} items")
501
+
502
+ # Test 3: collection.update - Update existing item
503
+ print(f"✅ Testing collection.update() - update existing item")
504
+ collection.update(
505
+ ids=test_id_1,
506
+ documents="Updated document 1",
507
+ metadatas={"category": "test", "score": 95, "updated": True}
508
+ )
509
+
510
+ # Verify update using collection.get
511
+ results = collection.get(ids=test_id_1)
512
+ assert len(results) == 1
513
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
514
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "Updated document 1"
515
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('score') == 95
516
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('updated') is True
517
+ print(f" Successfully updated and verified item with ID: {test_id_1}")
518
+
519
+ # Test 4: collection.update - Update multiple items with vectors
520
+ print(f"✅ Testing collection.update() - update multiple items with vectors")
521
+ collection.update(
522
+ ids=test_ids[:2],
523
+ vectors=[[2.1, 3.1, 4.1], [3.1, 4.1, 5.1]],
524
+ metadatas=[
525
+ {"category": "test", "score": 92},
526
+ {"category": "test", "score": 87}
527
+ ]
528
+ )
529
+
530
+ # Verify update using collection.get
531
+ results = collection.get(ids=test_ids[:2], include=["embeddings"])
532
+ assert len(results) == 2
533
+ print(f" Successfully updated and verified {len(results)} items with vectors")
534
+
535
+ # Test 5: collection.upsert - Upsert existing item (should update)
536
+ print(f"✅ Testing collection.upsert() - upsert existing item (update)")
537
+ collection.upsert(
538
+ ids=test_id_1,
539
+ documents="Upserted document 1",
540
+ metadatas={"category": "test", "score": 98}
541
+ )
542
+
543
+ # Verify upsert using collection.get
544
+ results = collection.get(ids=test_id_1)
545
+ assert len(results) == 1
546
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
547
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "Upserted document 1"
548
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('score') == 98
549
+ print(f" Successfully upserted (update) and verified item with ID: {test_id_1}")
550
+
551
+ # Test 6: collection.upsert - Upsert new item (should insert)
552
+ print(f"✅ Testing collection.upsert() - upsert new item (insert)")
553
+ test_id_new = str(uuid.uuid4())
554
+ collection.upsert(
555
+ ids=test_id_new,
556
+ vectors=[5.0, 6.0, 7.0],
557
+ documents="New upserted document",
558
+ metadatas={"category": "new", "score": 99}
559
+ )
560
+
561
+ # Verify upsert using collection.get
562
+ results = collection.get(ids=test_id_new)
563
+ assert len(results) == 1
564
+ result_dict = results[0].to_dict() if hasattr(results[0], 'to_dict') else results[0]
565
+ assert result_dict.get(CollectionFieldNames.DOCUMENT) == "New upserted document"
566
+ assert result_dict.get(CollectionFieldNames.METADATA, {}).get('category') == "new"
567
+ print(f" Successfully upserted (insert) and verified item with ID: {test_id_new}")
568
+
569
+ # Test 7: collection.delete - Delete by ID
570
+ print(f"✅ Testing collection.delete() - delete by ID")
571
+ # Delete one of the test items
572
+ collection.delete(ids=test_ids[0])
573
+
574
+ # Verify deletion using collection.get
575
+ results = collection.get(ids=test_ids[0])
576
+ assert len(results) == 0
577
+ print(f" Successfully deleted item with ID: {test_ids[0]}")
578
+
579
+ # Verify other items still exist
580
+ results = collection.get(ids=test_ids[1:])
581
+ assert len(results) == 2
582
+ print(f" Verified other items still exist")
583
+
584
+ # Test 8: collection.delete - Delete by metadata filter with comparison operator
585
+ print(f"✅ Testing collection.delete() - delete by metadata filter with $gte")
586
+ # Add items with different scores
587
+ test_id_score = str(uuid.uuid4())
588
+ collection.add(
589
+ ids=test_id_score,
590
+ vectors=[7.0, 8.0, 9.0],
591
+ documents="High score document",
592
+ metadatas={"category": "test", "score": 99}
593
+ )
594
+
595
+ # Delete items with score >= 99
596
+ collection.delete(where={"score": {"$gte": 99}})
597
+
598
+ # Verify deletion using collection.get
599
+ results = collection.get(where={"score": {"$gte": 99}})
600
+ assert len(results) == 0
601
+ print(f" Successfully deleted items with score >= 99")
602
+
603
+ # Test 9: collection.delete - Delete by document filter
604
+ print(f"✅ Testing collection.delete() - delete by document filter")
605
+ # Add an item with specific document content
606
+ test_id_doc = str(uuid.uuid4())
607
+ collection.add(
608
+ ids=test_id_doc,
609
+ vectors=[6.0, 7.0, 8.0],
610
+ documents="Delete this document",
611
+ metadatas={"category": "temp"}
612
+ )
613
+
614
+ # Delete by document filter
615
+ collection.delete(where_document={"$contains": "Delete this"})
616
+
617
+ # Verify deletion using collection.get
618
+ results = collection.get(where_document={"$contains": "Delete this"})
619
+ assert len(results) == 0
620
+ print(f" Successfully deleted items by document filter")
621
+
622
+ # Test 10: Verify final state using collection.get with filters
623
+ print(f"✅ Testing final state verification")
624
+ all_results = collection.get(limit=100)
625
+ print(f" Final collection count: {len(all_results)} items")
626
+ assert len(all_results) > 0
627
+
628
+ # Verify by category filter
629
+ test_results = collection.get(where={"category": {"$eq": "test"}})
630
+ print(f" Items with category='test': {len(test_results)}")
631
+
632
+ finally:
633
+ # Cleanup
634
+ try:
635
+ client.delete_collection(name=collection_name)
636
+ print(f" Cleaned up collection: {collection_name}")
637
+ except Exception as cleanup_error:
638
+ print(f" Warning: Failed to cleanup collection: {cleanup_error}")
639
+
640
+
641
+ if __name__ == "__main__":
642
+ print("\n" + "="*60)
643
+ print("SeekDBClient - Collection DML Tests")
644
+ print("="*60)
645
+ print(f"\nEnvironment Variable Configuration:")
646
+ print(f" Embedded mode: path={SEEKDB_PATH}, database={SEEKDB_DATABASE}")
647
+ print(f" Server mode: {SERVER_USER}@{SERVER_HOST}:{SERVER_PORT}/{SERVER_DATABASE}")
648
+ print(f" OceanBase mode: {OB_USER}@{OB_TENANT} -> {OB_HOST}:{OB_PORT}/{OB_DATABASE}")
649
+ print("="*60 + "\n")
650
+
651
+ pytest.main([__file__, "-v", "-s"])
652
+