Skip to content

Commit b599ebe

Browse files
authored
Merge pull request #4 from atasoglu/develop
v2.0.0
2 parents 6531a90 + 809570a commit b599ebe

File tree

11 files changed

+315
-285
lines changed

11 files changed

+315
-285
lines changed

CHANGELOG.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.0.0] - 2025-01-30
9+
10+
### Changed
11+
- **BREAKING:** Simplified `update_many()` - removed complex grouping logic (58% code reduction)
12+
- **BREAKING:** Renamed `get_by_id()``get()` for cleaner API
13+
- **BREAKING:** Renamed `delete_by_id()``delete()` for cleaner API
14+
15+
### Removed
16+
- **BREAKING:** Removed `get_by_text()` - use SQL queries or `get_all()` with filtering
17+
- **BREAKING:** Removed `get_by_metadata()` - use SQL queries or `get_all()` with filtering
18+
- **BREAKING:** Removed `list_results()` - use `get_all()` generator instead
19+
20+
### Added
21+
- Kept `count()` method for convenience (user request)
22+
23+
### Improved
24+
- 28% smaller codebase (650 → 467 lines)
25+
- 15% fewer methods (20 → 17)
26+
- Test coverage increased 89% → 92%
27+
- Cleaner, more intuitive API
28+
- Better code maintainability
29+
- All core CRUD and bulk operations preserved
30+
831
## [1.2.0] - 2025-01-29
932

1033
### Added
@@ -120,7 +143,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
120143

121144
## Version History
122145

123-
- **1.0.0** - First stable release with comprehensive features, bulk operations, logging, security improvements, and CI/CD
146+
- **2.0.0** - Major refactor: simplified API, removed niche methods, cleaner naming
147+
- **1.2.0** - Added benchmarks module
148+
- **1.0.0** - First stable release
124149
- **0.1.0** - Initial release
125150

126151
---

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,9 @@ Edit [benchmarks/config.yaml](benchmarks/config.yaml) to customize:
219219
- [TESTING.md](TESTING.md) - Testing documentation
220220
- [Examples](examples/) - Usage examples
221221
- [basic_usage.py](examples/basic_usage.py) - Basic CRUD operations
222-
- [logging_example.py](examples/logging_example.py) - Logging configuration
222+
- [transaction_example.py](examples/transaction_example.py) - Transaction management with all CRUD operations
223223
- [batch_operations.py](examples/batch_operations.py) - Bulk operations
224+
- [logging_example.py](examples/logging_example.py) - Logging configuration
224225
- [Benchmarks](benchmarks/) - Performance benchmarks
225226

226227
## Contributing

examples/basic_usage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def main():
4343
print(f" [{rowid}] {text[:50]}... (distance: {distance:.4f})")
4444

4545
# Get record by ID
46-
record = client.get_by_id(rowids[0])
46+
record = client.get(rowids[0])
4747
if record:
4848
rowid, text, metadata, embedding = record
4949
print(f"\nRecord {rowid}: {text}")

examples/batch_operations.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,12 @@ def main():
2626
rowids = client.add(texts=texts, embeddings=embeddings, metadata=metadata)
2727
print(f"Inserted {len(rowids)} products")
2828

29-
# Pagination - list first page
29+
# Pagination using get_all with batch_size
3030
page_size = 10
31-
page_1 = client.list_results(limit=page_size, offset=0, order="asc")
32-
print(f"\nPage 1 ({len(page_1)} items):")
33-
for rowid, text, meta, _ in page_1[:3]:
34-
print(f" [{rowid}] {text} - ${meta['price']}")
35-
36-
# Pagination - list second page
37-
page_2 = client.list_results(limit=page_size, offset=page_size, order="asc")
38-
print(f"\nPage 2 ({len(page_2)} items):")
39-
for rowid, text, meta, _ in page_2[:3]:
31+
print(f"\nFirst {page_size} items:")
32+
for i, (rowid, text, meta, _) in enumerate(client.get_all(batch_size=page_size)):
33+
if i >= 3:
34+
break
4035
print(f" [{rowid}] {text} - ${meta['price']}")
4136

4237
# Batch retrieval

examples/metadata_filtering.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
33
Demonstrates:
44
- Adding records with metadata
5-
- Filtering by metadata
6-
- Filtering by text
5+
- Querying records with get_all
76
- Updating metadata
87
"""
98

@@ -36,17 +35,17 @@ def main():
3635
rowids = client.add(texts=texts, embeddings=embeddings, metadata=metadata)
3736
print(f"Added {len(rowids)} articles")
3837

39-
# Filter by exact metadata match
40-
alice_articles = client.get_by_metadata(
41-
{"category": "programming", "author": "Alice", "year": 2023}
42-
)
43-
print(f"\nAlice's programming articles: {len(alice_articles)}")
44-
for rowid, text, meta, _ in alice_articles:
45-
print(f" [{rowid}] {text} - {meta}")
38+
# Query all articles and filter by author
39+
print("\nAlice's articles:")
40+
for rowid, text, meta, _ in client.get_all():
41+
if meta.get("author") == "Alice":
42+
print(f" [{rowid}] {text} - {meta}")
4643

47-
# Filter by text
48-
python_articles = client.get_by_text("Python for data science")
49-
print(f"\nPython articles: {len(python_articles)}")
44+
# Query all articles and filter by text
45+
print("\nPython-related articles:")
46+
for rowid, text, meta, _ in client.get_all():
47+
if "Python" in text:
48+
print(f" [{rowid}] {text}")
5049

5150
# Update metadata
5251
if rowids:
@@ -59,7 +58,7 @@ def main():
5958
"updated": True,
6059
},
6160
)
62-
updated = client.get_by_id(rowids[0])
61+
updated = client.get(rowids[0])
6362
if updated:
6463
print(f"\nUpdated metadata: {updated[2]}")
6564

examples/real_world_scenario.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,22 @@ def main():
8181

8282
print("Top 3 results:")
8383
for i, (rowid, text, distance) in enumerate(results, 1):
84-
record = client.get_by_id(rowid)
84+
record = client.get(rowid)
8585
if record:
8686
_, _, meta, _ = record
8787
print(f" {i}. [{meta['category']}] {text[:60]}...")
8888
print(
8989
f" Distance: {distance:.4f}, Difficulty: {meta['difficulty']}\n"
9090
)
9191

92-
# Filter by category
93-
print("All AI-related documents:")
94-
ai_docs = client.get_by_metadata(
95-
{"category": "ai", "language": "general", "difficulty": "intermediate"}
96-
)
97-
for rowid, text, meta, _ in ai_docs:
98-
print(f" • {text[:60]}...")
92+
# Filter by category using get_all
93+
print("All AI-related documents (intermediate):")
94+
for rowid, text, meta, _ in client.get_all():
95+
if (
96+
meta.get("category") == "ai"
97+
and meta.get("difficulty") == "intermediate"
98+
):
99+
print(f" • {text[:60]}...")
99100

100101
# Update document
101102
if rowids:
@@ -114,9 +115,12 @@ def main():
114115
print("\nKnowledge base statistics:")
115116
print(f" Total documents: {client.count()}")
116117

117-
# List recent documents
118-
recent = client.list_results(limit=3, offset=0, order="desc")
119-
print(f" Most recent: {len(recent)} documents")
118+
# List first 3 documents
119+
print(" First 3 documents:")
120+
for i, (rowid, text, _, _) in enumerate(client.get_all()):
121+
if i >= 3:
122+
break
123+
print(f" [{rowid}] {text[:50]}...")
120124

121125

122126
if __name__ == "__main__":

examples/transaction_example.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
"""Transaction example for sqlite-vec-client.
2+
3+
Demonstrates:
4+
- Atomic transactions with context manager
5+
- All CRUD operations in a single transaction
6+
- Rollback on error
7+
- Transaction isolation
8+
"""
9+
10+
from sqlite_vec_client import SQLiteVecClient
11+
12+
13+
def main():
14+
client = SQLiteVecClient(table="products", db_path=":memory:")
15+
client.create_table(dim=64, distance="cosine")
16+
17+
# Example 1: Successful transaction with all CRUD operations
18+
print("Example 1: Successful transaction")
19+
print("-" * 50)
20+
21+
with client.transaction():
22+
# CREATE: Add initial products
23+
texts = [f"Product {i}" for i in range(5)]
24+
embeddings = [[float(i)] * 64 for i in range(5)]
25+
metadata = [{"price": i * 10, "stock": 100} for i in range(5)]
26+
rowids = client.add(texts=texts, embeddings=embeddings, metadata=metadata)
27+
print(f"[+] Added {len(rowids)} products: {rowids}")
28+
29+
# READ: Get a product
30+
product = client.get(rowids[0])
31+
if product:
32+
print(f"[+] Retrieved product {product[0]}: {product[1]}")
33+
34+
# UPDATE: Update single product
35+
updated = client.update(
36+
rowids[0], text="Updated Product 0", metadata={"price": 99}
37+
)
38+
print(f"[+] Updated product {rowids[0]}: {updated}")
39+
40+
# UPDATE: Bulk update
41+
updates = [
42+
(rowids[1], "Bulk Updated 1", {"price": 150}, None),
43+
(rowids[2], None, {"price": 200, "stock": 50}, None),
44+
]
45+
count = client.update_many(updates)
46+
print(f"[+] Bulk updated {count} products")
47+
48+
# DELETE: Delete single product
49+
deleted = client.delete(rowids[3])
50+
print(f"[+] Deleted product {rowids[3]}: {deleted}")
51+
52+
# DELETE: Bulk delete
53+
deleted_count = client.delete_many([rowids[4]])
54+
print(f"[+] Bulk deleted {deleted_count} products")
55+
56+
# Transaction committed - verify results
57+
print("\n[+] Transaction committed successfully")
58+
print(f" Total products remaining: {client.count()}")
59+
60+
# Example 2: Failed transaction with rollback
61+
print("\n\nExample 2: Failed transaction (rollback)")
62+
print("-" * 50)
63+
64+
initial_count = client.count()
65+
print(f"Initial count: {initial_count}")
66+
67+
try:
68+
with client.transaction():
69+
# Add more products
70+
new_texts = ["New Product 1", "New Product 2"]
71+
new_embeddings = [[1.0] * 64, [2.0] * 64]
72+
new_rowids = client.add(texts=new_texts, embeddings=new_embeddings)
73+
print(f"[+] Added {len(new_rowids)} products: {new_rowids}")
74+
75+
# Update existing
76+
client.update(rowids[0], text="This will be rolled back")
77+
print(f"[+] Updated product {rowids[0]}")
78+
79+
# Simulate error
80+
raise ValueError("Simulated error - transaction will rollback")
81+
82+
except ValueError as e:
83+
print(f"\n[-] Error occurred: {e}")
84+
print("[+] Transaction rolled back automatically")
85+
86+
# Verify rollback
87+
final_count = client.count()
88+
print(f" Final count: {final_count}")
89+
print(f" Count unchanged: {initial_count == final_count}")
90+
91+
# Verify data not changed
92+
product = client.get(rowids[0])
93+
if product:
94+
print(f" Product {rowids[0]} text: {product[1]}")
95+
96+
# Example 3: Nested operations with similarity search
97+
print("\n\nExample 3: Complex transaction with search")
98+
print("-" * 50)
99+
100+
with client.transaction():
101+
# Add products with similar embeddings
102+
similar_texts = ["Red Apple", "Green Apple", "Orange"]
103+
similar_embeddings = [
104+
[0.9, 0.1] + [0.0] * 62,
105+
[0.85, 0.15] + [0.0] * 62,
106+
[0.5, 0.5] + [0.0] * 62,
107+
]
108+
similar_rowids = client.add(texts=similar_texts, embeddings=similar_embeddings)
109+
print(f"[+] Added {len(similar_rowids)} products")
110+
111+
# Search within transaction
112+
query_emb = [0.9, 0.1] + [0.0] * 62
113+
results = client.similarity_search(embedding=query_emb, top_k=2)
114+
print(f"[+] Found {len(results)} similar products:")
115+
for rowid, text, distance in results:
116+
dist_str = f"{distance:.4f}" if distance is not None else "N/A"
117+
print(f" [{rowid}] {text} (distance: {dist_str})")
118+
119+
# Update based on search results
120+
for rowid, text, distance in results:
121+
if distance is not None and distance < 0.1:
122+
client.update(rowid, metadata={"featured": True})
123+
print(f"[+] Marked product {rowid} as featured")
124+
125+
print("\n[+] Complex transaction completed")
126+
print(f" Total products: {client.count()}")
127+
128+
# Example 4: Batch operations in transaction
129+
print("\n\nExample 4: Large batch operations")
130+
print("-" * 50)
131+
132+
with client.transaction():
133+
# Bulk insert
134+
batch_size = 20
135+
batch_texts = [f"Batch Product {i}" for i in range(batch_size)]
136+
batch_embeddings = [[float(i % 10)] * 64 for i in range(batch_size)]
137+
batch_rowids = client.add(texts=batch_texts, embeddings=batch_embeddings)
138+
print(f"[+] Bulk inserted {len(batch_rowids)} products")
139+
140+
# Bulk update all
141+
bulk_updates = [
142+
(rid, None, {"batch": True, "processed": True}, None)
143+
for rid in batch_rowids[:10]
144+
]
145+
updated = client.update_many(bulk_updates)
146+
print(f"[+] Bulk updated {updated} products")
147+
148+
# Bulk delete some
149+
deleted = client.delete_many(batch_rowids[10:15])
150+
print(f"[+] Bulk deleted {deleted} products")
151+
152+
print("\n[+] Batch operations completed")
153+
print(f" Final total: {client.count()}")
154+
155+
client.close()
156+
157+
158+
if __name__ == "__main__":
159+
main()

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "sqlite-vec-client"
7-
version = "1.2.0"
7+
version = "2.0.0"
88
description = "A tiny Python client around sqlite-vec for CRUD and similarity search."
99
readme = "README.md"
1010
requires-python = ">=3.9"

0 commit comments

Comments
 (0)