sqlobjects 0.2.0__tar.gz → 1.0.0__tar.gz
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.
- sqlobjects-1.0.0/PKG-INFO +354 -0
- sqlobjects-1.0.0/README.md +324 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/pyproject.toml +6 -10
- sqlobjects-1.0.0/sqlobjects/__init__.py +34 -0
- sqlobjects-1.0.0/sqlobjects/database/__init__.py +29 -0
- {sqlobjects-0.2.0/sqlobjects → sqlobjects-1.0.0/sqlobjects/database}/config.py +6 -6
- sqlobjects-0.2.0/sqlobjects/database.py → sqlobjects-1.0.0/sqlobjects/database/manager.py +127 -127
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects/exceptions.py +0 -61
- sqlobjects-1.0.0/sqlobjects/expressions/__init__.py +40 -0
- sqlobjects-1.0.0/sqlobjects/expressions/aggregate.py +108 -0
- sqlobjects-1.0.0/sqlobjects/expressions/base.py +144 -0
- sqlobjects-1.0.0/sqlobjects/expressions/function.py +325 -0
- sqlobjects-1.0.0/sqlobjects/expressions/mixins.py +283 -0
- sqlobjects-1.0.0/sqlobjects/expressions/scalar.py +171 -0
- sqlobjects-1.0.0/sqlobjects/expressions/subquery.py +393 -0
- sqlobjects-1.0.0/sqlobjects/expressions/terminal.py +280 -0
- sqlobjects-1.0.0/sqlobjects/fields/__init__.py +58 -0
- sqlobjects-1.0.0/sqlobjects/fields/core.py +704 -0
- sqlobjects-1.0.0/sqlobjects/fields/functions.py +96 -0
- sqlobjects-1.0.0/sqlobjects/fields/proxies.py +157 -0
- sqlobjects-1.0.0/sqlobjects/fields/relations/__init__.py +31 -0
- sqlobjects-1.0.0/sqlobjects/fields/relations/descriptors.py +147 -0
- sqlobjects-1.0.0/sqlobjects/fields/relations/managers.py +76 -0
- sqlobjects-1.0.0/sqlobjects/fields/relations/proxies.py +411 -0
- sqlobjects-1.0.0/sqlobjects/fields/relations/utils.py +177 -0
- sqlobjects-1.0.0/sqlobjects/fields/shortcuts.py +675 -0
- sqlobjects-1.0.0/sqlobjects/fields/types/__init__.py +27 -0
- sqlobjects-1.0.0/sqlobjects/fields/types/base.py +17 -0
- sqlobjects-1.0.0/sqlobjects/fields/types/comparators.py +348 -0
- sqlobjects-1.0.0/sqlobjects/fields/types/registry.py +435 -0
- sqlobjects-1.0.0/sqlobjects/fields/utils.py +108 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects/metadata.py +37 -31
- sqlobjects-0.2.0/sqlobjects/model.py → sqlobjects-1.0.0/sqlobjects/mixins.py +11 -471
- sqlobjects-1.0.0/sqlobjects/model.py +294 -0
- sqlobjects-1.0.0/sqlobjects/objects/__init__.py +15 -0
- sqlobjects-1.0.0/sqlobjects/objects/bulk.py +812 -0
- sqlobjects-0.2.0/sqlobjects/objects.py → sqlobjects-1.0.0/sqlobjects/objects/core.py +351 -383
- sqlobjects-1.0.0/sqlobjects/queries/__init__.py +10 -0
- sqlobjects-1.0.0/sqlobjects/queries/builder.py +635 -0
- sqlobjects-1.0.0/sqlobjects/queries/executor.py +497 -0
- sqlobjects-1.0.0/sqlobjects/queryset.py +1153 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects/session.py +120 -160
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects/signals.py +8 -14
- sqlobjects-1.0.0/sqlobjects/utils/inspect.py +80 -0
- sqlobjects-1.0.0/sqlobjects/validators.py +322 -0
- sqlobjects-1.0.0/sqlobjects.egg-info/PKG-INFO +354 -0
- sqlobjects-1.0.0/sqlobjects.egg-info/SOURCES.txt +53 -0
- sqlobjects-0.2.0/PKG-INFO +0 -29
- sqlobjects-0.2.0/sqlobjects/__init__.py +0 -38
- sqlobjects-0.2.0/sqlobjects/expressions.py +0 -1087
- sqlobjects-0.2.0/sqlobjects/fields.py +0 -2592
- sqlobjects-0.2.0/sqlobjects/history.py +0 -101
- sqlobjects-0.2.0/sqlobjects/queries.py +0 -1858
- sqlobjects-0.2.0/sqlobjects/relations.py +0 -841
- sqlobjects-0.2.0/sqlobjects/validators.py +0 -294
- sqlobjects-0.2.0/sqlobjects.egg-info/PKG-INFO +0 -29
- sqlobjects-0.2.0/sqlobjects.egg-info/SOURCES.txt +0 -25
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/LICENSE +0 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/setup.cfg +0 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects/utils/__init__.py +0 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects/utils/naming.py +0 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects/utils/pattern.py +0 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects.egg-info/dependency_links.txt +0 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects.egg-info/requires.txt +0 -0
- {sqlobjects-0.2.0 → sqlobjects-1.0.0}/sqlobjects.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sqlobjects
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Django-style async ORM library based on SQLAlchemy with chainable queries, Q objects, and relationship loading
|
|
5
|
+
Author-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
|
|
6
|
+
Maintainer-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/XtraVisionsAI/sqlobjects
|
|
9
|
+
Project-URL: Repository, https://github.com/XtraVisionsAI/sqlobjects.git
|
|
10
|
+
Project-URL: Documentation, https://github.com/XtraVisionsAI/sqlobjects#readme
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/XtraVisionsAI/sqlobjects/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/XtraVisionsAI/sqlobjects/blob/main/CHANGELOG.md
|
|
13
|
+
Keywords: python,orm,async,django-style,database,query
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Topic :: Database
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Framework :: AsyncIO
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.12
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.43
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# SQLObjects
|
|
32
|
+
|
|
33
|
+
[English](README.md) | [中文](README.zh-CN.md)
|
|
34
|
+
|
|
35
|
+
[](https://www.python.org/downloads/)
|
|
36
|
+
[](https://opensource.org/licenses/MIT)
|
|
37
|
+
[](https://github.com/astral-sh/ruff)
|
|
38
|
+
[](https://github.com/microsoft/pyright)
|
|
39
|
+
|
|
40
|
+
A modern, Django-style async ORM library built on SQLAlchemy Core with chainable queries, Q objects, and relationship
|
|
41
|
+
loading. SQLObjects combines the familiar Django ORM API with the performance and flexibility of SQLAlchemy Core.
|
|
42
|
+
|
|
43
|
+
## ✨ Key Features
|
|
44
|
+
|
|
45
|
+
- **🚀 Django-style API** - Familiar and intuitive interface for Django developers
|
|
46
|
+
- **⚡ Async-first design** - Built for modern async Python applications
|
|
47
|
+
- **🔗 Chainable queries** - Fluent query building with method chaining
|
|
48
|
+
- **🎯 Type safety** - Full type annotations and runtime validation
|
|
49
|
+
- **📊 High performance** - Built on SQLAlchemy Core for optimal performance
|
|
50
|
+
- **🔄 Smart operations** - Automatic CREATE/UPDATE detection and bulk operations
|
|
51
|
+
- **🎣 Lifecycle hooks** - Comprehensive signal system for database operations
|
|
52
|
+
- **🗄️ Multi-database support** - Seamless multi-database configuration and routing
|
|
53
|
+
|
|
54
|
+
## 🚀 Quick Start
|
|
55
|
+
|
|
56
|
+
### Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install sqlobjects
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Basic Usage
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from sqlobjects.model import ObjectModel
|
|
66
|
+
from sqlobjects.fields import Column, StringColumn, IntegerColumn, BooleanColumn
|
|
67
|
+
from sqlobjects.database import init_db, create_tables
|
|
68
|
+
|
|
69
|
+
# Define your models
|
|
70
|
+
class User(ObjectModel):
|
|
71
|
+
username: Column[str] = StringColumn(length=50, unique=True)
|
|
72
|
+
email: Column[str] = StringColumn(length=100, unique=True)
|
|
73
|
+
age: Column[int] = IntegerColumn(nullable=True)
|
|
74
|
+
is_active: Column[bool] = BooleanColumn(default=True)
|
|
75
|
+
|
|
76
|
+
# Initialize database
|
|
77
|
+
await init_db("sqlite+aiosqlite:///app.db")
|
|
78
|
+
await create_tables(ObjectModel)
|
|
79
|
+
|
|
80
|
+
# Create and query data
|
|
81
|
+
user = await User.objects.create(
|
|
82
|
+
username="alice",
|
|
83
|
+
email="alice@example.com",
|
|
84
|
+
age=25
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Chainable queries with Django-style API
|
|
88
|
+
active_users = await User.objects.filter(
|
|
89
|
+
User.is_active == True
|
|
90
|
+
).order_by("-age").limit(10).all()
|
|
91
|
+
|
|
92
|
+
# Complex queries with Q objects
|
|
93
|
+
from sqlobjects.queries import Q
|
|
94
|
+
|
|
95
|
+
users = await User.objects.filter(
|
|
96
|
+
Q(User.age >= 18) & (Q(User.username.like("%admin%")) | Q(User.is_active == True))
|
|
97
|
+
).all()
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 📚 Core Concepts
|
|
101
|
+
|
|
102
|
+
### Model Definition
|
|
103
|
+
|
|
104
|
+
SQLObjects uses a Django-style model definition with automatic table generation:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from sqlobjects.model import ObjectModel
|
|
108
|
+
from sqlobjects.fields import Column, StringColumn, DateTimeColumn, foreign_key
|
|
109
|
+
from datetime import datetime
|
|
110
|
+
|
|
111
|
+
class Post(ObjectModel):
|
|
112
|
+
title: Column[str] = StringColumn(length=200)
|
|
113
|
+
content: Column[str] = StringColumn(type="text")
|
|
114
|
+
author_id: Column[int] = foreign_key("users.id")
|
|
115
|
+
created_at: Column[datetime] = DateTimeColumn(default_factory=datetime.now)
|
|
116
|
+
|
|
117
|
+
class Config:
|
|
118
|
+
table_name = "blog_posts" # Custom table name
|
|
119
|
+
ordering = ["-created_at"] # Default ordering
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Query Building
|
|
123
|
+
|
|
124
|
+
Build complex queries with chainable methods:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# Basic filtering and ordering
|
|
128
|
+
posts = await Post.objects.filter(
|
|
129
|
+
Post.title.like("%python%")
|
|
130
|
+
).order_by("-created_at").limit(5).all()
|
|
131
|
+
|
|
132
|
+
# Aggregation and annotation
|
|
133
|
+
from sqlobjects.expressions import func
|
|
134
|
+
|
|
135
|
+
user_stats = await User.objects.annotate(
|
|
136
|
+
post_count=func.count(User.posts),
|
|
137
|
+
latest_post=func.max(User.posts.created_at)
|
|
138
|
+
).filter(User.post_count > 0).all()
|
|
139
|
+
|
|
140
|
+
# Relationship loading
|
|
141
|
+
posts = await Post.objects.select_related("author").prefetch_related("comments").all()
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Bulk Operations
|
|
145
|
+
|
|
146
|
+
High-performance bulk operations for large datasets:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
# Bulk create (10-100x faster than individual creates)
|
|
150
|
+
users_data = [
|
|
151
|
+
{"username": f"user{i}", "email": f"user{i}@example.com"}
|
|
152
|
+
for i in range(1000)
|
|
153
|
+
]
|
|
154
|
+
await User.objects.bulk_create(users_data, batch_size=500)
|
|
155
|
+
|
|
156
|
+
# Bulk update
|
|
157
|
+
mappings = [
|
|
158
|
+
{"id": 1, "is_active": False},
|
|
159
|
+
{"id": 2, "is_active": True},
|
|
160
|
+
]
|
|
161
|
+
await User.objects.bulk_update(mappings, match_fields=["id"])
|
|
162
|
+
|
|
163
|
+
# Bulk delete
|
|
164
|
+
user_ids = [1, 2, 3, 4, 5]
|
|
165
|
+
await User.objects.bulk_delete(user_ids, id_field="id")
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Session Management
|
|
169
|
+
|
|
170
|
+
Flexible session and transaction management:
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from sqlobjects.session import ctx_session, ctx_sessions
|
|
174
|
+
|
|
175
|
+
# Single database transaction
|
|
176
|
+
async with ctx_session() as session:
|
|
177
|
+
user = await User.objects.using(session).create(username="bob")
|
|
178
|
+
posts = await user.posts.using(session).all()
|
|
179
|
+
# Automatic commit on success, rollback on error
|
|
180
|
+
|
|
181
|
+
# Multi-database transactions
|
|
182
|
+
async with ctx_sessions("main", "analytics") as sessions:
|
|
183
|
+
user = await User.objects.using(sessions["main"]).create(username="alice")
|
|
184
|
+
await Log.objects.using(sessions["analytics"]).create(message="User created")
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Lifecycle Hooks
|
|
188
|
+
|
|
189
|
+
Comprehensive signal system for database operations:
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
class User(ObjectModel):
|
|
193
|
+
username: Column[str] = StringColumn(length=50)
|
|
194
|
+
|
|
195
|
+
async def before_save(self, context):
|
|
196
|
+
"""Called before any save operation"""
|
|
197
|
+
self.updated_at = datetime.now()
|
|
198
|
+
|
|
199
|
+
async def after_create(self, context):
|
|
200
|
+
"""Called only after creation"""
|
|
201
|
+
await self.send_welcome_email()
|
|
202
|
+
|
|
203
|
+
async def before_delete(self, context):
|
|
204
|
+
"""Called before deletion"""
|
|
205
|
+
await self.cleanup_related_data()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 🏗️ Architecture
|
|
209
|
+
|
|
210
|
+
SQLObjects is built on a solid foundation with clear architectural principles:
|
|
211
|
+
|
|
212
|
+
- **SQLAlchemy Core** - Maximum performance and control over SQL generation
|
|
213
|
+
- **Async-first** - Native async/await support throughout the library
|
|
214
|
+
- **Type safety** - Comprehensive type annotations and runtime validation
|
|
215
|
+
- **Modular design** - Clean separation of concerns and extensible architecture
|
|
216
|
+
|
|
217
|
+
## 📖 Documentation
|
|
218
|
+
|
|
219
|
+
### Feature Documentation
|
|
220
|
+
|
|
221
|
+
- [Database Setup](docs/features/01-database-setup.md) - Database configuration and connection management
|
|
222
|
+
- [Model Definition](docs/features/02-model-definition.md) - Model creation, fields, and validation
|
|
223
|
+
- [Querying Data](docs/features/03-querying-data.md) - Query building, filtering, and aggregation
|
|
224
|
+
- [CRUD Operations](docs/features/04-crud-operations.md) - Create, read, update, delete operations
|
|
225
|
+
- [Relationships](docs/features/05-relationships.md) - Model relationships and loading strategies
|
|
226
|
+
- [Validation & Signals](docs/features/06-validation-signals.md) - Data validation and lifecycle hooks
|
|
227
|
+
- [Performance Optimization](docs/features/07-performance-optimization.md) - Performance tuning and best practices
|
|
228
|
+
|
|
229
|
+
### Design Documentation
|
|
230
|
+
|
|
231
|
+
- [Core Architecture](docs/design/01-core-architecture.md) - System architecture and design principles
|
|
232
|
+
- [Data Operations](docs/design/02-data-operations.md) - Query execution and data processing
|
|
233
|
+
- [Field System](docs/design/03-field-system.md) - Field types and type system
|
|
234
|
+
- [Relationships](docs/design/04-relationships.md) - Relationship implementation details
|
|
235
|
+
- [Extensions](docs/design/05-extensions.md) - Extension points and customization
|
|
236
|
+
|
|
237
|
+
## 🔧 Advanced Features
|
|
238
|
+
|
|
239
|
+
### Multi-Database Support
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
from sqlobjects.database import init_dbs
|
|
243
|
+
|
|
244
|
+
# Configure multiple databases
|
|
245
|
+
main_db, analytics_db = await init_dbs({
|
|
246
|
+
"main": {"url": "postgresql+asyncpg://user:pass@localhost/main"},
|
|
247
|
+
"analytics": {"url": "sqlite+aiosqlite:///analytics.db"}
|
|
248
|
+
}, default="main")
|
|
249
|
+
|
|
250
|
+
# Use specific databases
|
|
251
|
+
user = await User.objects.using("analytics").create(username="analyst")
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Performance Optimization
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
# Memory-efficient iteration for large datasets
|
|
258
|
+
async for user in User.objects.iterator(chunk_size=1000):
|
|
259
|
+
await process_user(user)
|
|
260
|
+
|
|
261
|
+
# Cache control for performance
|
|
262
|
+
users = await User.objects.filter(User.is_active == True).all() # Uses cache
|
|
263
|
+
live_data = await User.objects.no_cache().filter(User.status == "online").all() # Skip cache
|
|
264
|
+
|
|
265
|
+
# Field-level performance optimization
|
|
266
|
+
class User(ObjectModel):
|
|
267
|
+
bio: Column[str] = column(type="text", deferred=True) # Lazy loading
|
|
268
|
+
profile_image: Column[bytes] = column(type="binary", deferred=True)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Advanced Querying
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
# Subqueries and complex conditions
|
|
275
|
+
avg_age = User.objects.aggregate(avg_age=func.avg(User.age)).subquery(query_type="scalar")
|
|
276
|
+
older_users = await User.objects.filter(User.age > avg_age).all()
|
|
277
|
+
|
|
278
|
+
# Manual joins and locking
|
|
279
|
+
posts = await Post.objects.join(
|
|
280
|
+
User.__table__,
|
|
281
|
+
Post.author_id == User.id
|
|
282
|
+
).select_for_update(nowait=True).all()
|
|
283
|
+
|
|
284
|
+
# Raw SQL when needed
|
|
285
|
+
users = await User.objects.raw(
|
|
286
|
+
"SELECT * FROM users WHERE age > :age",
|
|
287
|
+
{"age": 18}
|
|
288
|
+
)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## 🧪 Testing
|
|
292
|
+
|
|
293
|
+
SQLObjects includes comprehensive test coverage:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
# Run all tests
|
|
297
|
+
uv run pytest
|
|
298
|
+
|
|
299
|
+
# Run specific test categories
|
|
300
|
+
uv run pytest tests/unit/ # Unit tests
|
|
301
|
+
uv run pytest tests/integration/ # Integration tests
|
|
302
|
+
uv run pytest tests/performance/ # Performance tests
|
|
303
|
+
|
|
304
|
+
# Run with coverage
|
|
305
|
+
uv run pytest --cov=sqlobjects
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## 🤝 Contributing
|
|
309
|
+
|
|
310
|
+
We welcome contributions! Please see our development guidelines:
|
|
311
|
+
|
|
312
|
+
1. **Design-first approach** - All changes start with design analysis
|
|
313
|
+
2. **Type safety** - Maintain comprehensive type annotations
|
|
314
|
+
3. **Test coverage** - Include tests for all new functionality
|
|
315
|
+
4. **Documentation** - Update docs for any API changes
|
|
316
|
+
|
|
317
|
+
### Development Setup
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
# Clone the repository
|
|
321
|
+
git clone https://github.com/XtraVisionsAI/sqlobjects.git
|
|
322
|
+
cd sqlobjects
|
|
323
|
+
|
|
324
|
+
# Install development dependencies
|
|
325
|
+
uv sync --group dev --group test
|
|
326
|
+
|
|
327
|
+
# Run pre-commit hooks
|
|
328
|
+
uv run pre-commit install
|
|
329
|
+
|
|
330
|
+
# Run tests
|
|
331
|
+
uv run pytest
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## 📋 Roadmap
|
|
335
|
+
|
|
336
|
+
See our [TODO.md](TODO.md) for planned features:
|
|
337
|
+
|
|
338
|
+
- **v2.0**: Database health checks, window functions, advanced bulk operations
|
|
339
|
+
- **v2.1**: Advanced cache management, query optimization tools
|
|
340
|
+
- **v2.2+**: CTE support, advanced SQL functions
|
|
341
|
+
|
|
342
|
+
## 📄 License
|
|
343
|
+
|
|
344
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
345
|
+
|
|
346
|
+
## 🙏 Acknowledgments
|
|
347
|
+
|
|
348
|
+
- Built on the excellent [SQLAlchemy](https://www.sqlalchemy.org/) library
|
|
349
|
+
- Inspired by [Django ORM](https://docs.djangoproject.com/en/stable/topics/db/) API design
|
|
350
|
+
- Thanks to all contributors and the Python async ecosystem
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
**SQLObjects** - Modern async ORM for Python 3.12+
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# SQLObjects
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://github.com/astral-sh/ruff)
|
|
8
|
+
[](https://github.com/microsoft/pyright)
|
|
9
|
+
|
|
10
|
+
A modern, Django-style async ORM library built on SQLAlchemy Core with chainable queries, Q objects, and relationship
|
|
11
|
+
loading. SQLObjects combines the familiar Django ORM API with the performance and flexibility of SQLAlchemy Core.
|
|
12
|
+
|
|
13
|
+
## ✨ Key Features
|
|
14
|
+
|
|
15
|
+
- **🚀 Django-style API** - Familiar and intuitive interface for Django developers
|
|
16
|
+
- **⚡ Async-first design** - Built for modern async Python applications
|
|
17
|
+
- **🔗 Chainable queries** - Fluent query building with method chaining
|
|
18
|
+
- **🎯 Type safety** - Full type annotations and runtime validation
|
|
19
|
+
- **📊 High performance** - Built on SQLAlchemy Core for optimal performance
|
|
20
|
+
- **🔄 Smart operations** - Automatic CREATE/UPDATE detection and bulk operations
|
|
21
|
+
- **🎣 Lifecycle hooks** - Comprehensive signal system for database operations
|
|
22
|
+
- **🗄️ Multi-database support** - Seamless multi-database configuration and routing
|
|
23
|
+
|
|
24
|
+
## 🚀 Quick Start
|
|
25
|
+
|
|
26
|
+
### Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install sqlobjects
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Basic Usage
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from sqlobjects.model import ObjectModel
|
|
36
|
+
from sqlobjects.fields import Column, StringColumn, IntegerColumn, BooleanColumn
|
|
37
|
+
from sqlobjects.database import init_db, create_tables
|
|
38
|
+
|
|
39
|
+
# Define your models
|
|
40
|
+
class User(ObjectModel):
|
|
41
|
+
username: Column[str] = StringColumn(length=50, unique=True)
|
|
42
|
+
email: Column[str] = StringColumn(length=100, unique=True)
|
|
43
|
+
age: Column[int] = IntegerColumn(nullable=True)
|
|
44
|
+
is_active: Column[bool] = BooleanColumn(default=True)
|
|
45
|
+
|
|
46
|
+
# Initialize database
|
|
47
|
+
await init_db("sqlite+aiosqlite:///app.db")
|
|
48
|
+
await create_tables(ObjectModel)
|
|
49
|
+
|
|
50
|
+
# Create and query data
|
|
51
|
+
user = await User.objects.create(
|
|
52
|
+
username="alice",
|
|
53
|
+
email="alice@example.com",
|
|
54
|
+
age=25
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Chainable queries with Django-style API
|
|
58
|
+
active_users = await User.objects.filter(
|
|
59
|
+
User.is_active == True
|
|
60
|
+
).order_by("-age").limit(10).all()
|
|
61
|
+
|
|
62
|
+
# Complex queries with Q objects
|
|
63
|
+
from sqlobjects.queries import Q
|
|
64
|
+
|
|
65
|
+
users = await User.objects.filter(
|
|
66
|
+
Q(User.age >= 18) & (Q(User.username.like("%admin%")) | Q(User.is_active == True))
|
|
67
|
+
).all()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 📚 Core Concepts
|
|
71
|
+
|
|
72
|
+
### Model Definition
|
|
73
|
+
|
|
74
|
+
SQLObjects uses a Django-style model definition with automatic table generation:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from sqlobjects.model import ObjectModel
|
|
78
|
+
from sqlobjects.fields import Column, StringColumn, DateTimeColumn, foreign_key
|
|
79
|
+
from datetime import datetime
|
|
80
|
+
|
|
81
|
+
class Post(ObjectModel):
|
|
82
|
+
title: Column[str] = StringColumn(length=200)
|
|
83
|
+
content: Column[str] = StringColumn(type="text")
|
|
84
|
+
author_id: Column[int] = foreign_key("users.id")
|
|
85
|
+
created_at: Column[datetime] = DateTimeColumn(default_factory=datetime.now)
|
|
86
|
+
|
|
87
|
+
class Config:
|
|
88
|
+
table_name = "blog_posts" # Custom table name
|
|
89
|
+
ordering = ["-created_at"] # Default ordering
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Query Building
|
|
93
|
+
|
|
94
|
+
Build complex queries with chainable methods:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
# Basic filtering and ordering
|
|
98
|
+
posts = await Post.objects.filter(
|
|
99
|
+
Post.title.like("%python%")
|
|
100
|
+
).order_by("-created_at").limit(5).all()
|
|
101
|
+
|
|
102
|
+
# Aggregation and annotation
|
|
103
|
+
from sqlobjects.expressions import func
|
|
104
|
+
|
|
105
|
+
user_stats = await User.objects.annotate(
|
|
106
|
+
post_count=func.count(User.posts),
|
|
107
|
+
latest_post=func.max(User.posts.created_at)
|
|
108
|
+
).filter(User.post_count > 0).all()
|
|
109
|
+
|
|
110
|
+
# Relationship loading
|
|
111
|
+
posts = await Post.objects.select_related("author").prefetch_related("comments").all()
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Bulk Operations
|
|
115
|
+
|
|
116
|
+
High-performance bulk operations for large datasets:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# Bulk create (10-100x faster than individual creates)
|
|
120
|
+
users_data = [
|
|
121
|
+
{"username": f"user{i}", "email": f"user{i}@example.com"}
|
|
122
|
+
for i in range(1000)
|
|
123
|
+
]
|
|
124
|
+
await User.objects.bulk_create(users_data, batch_size=500)
|
|
125
|
+
|
|
126
|
+
# Bulk update
|
|
127
|
+
mappings = [
|
|
128
|
+
{"id": 1, "is_active": False},
|
|
129
|
+
{"id": 2, "is_active": True},
|
|
130
|
+
]
|
|
131
|
+
await User.objects.bulk_update(mappings, match_fields=["id"])
|
|
132
|
+
|
|
133
|
+
# Bulk delete
|
|
134
|
+
user_ids = [1, 2, 3, 4, 5]
|
|
135
|
+
await User.objects.bulk_delete(user_ids, id_field="id")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Session Management
|
|
139
|
+
|
|
140
|
+
Flexible session and transaction management:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from sqlobjects.session import ctx_session, ctx_sessions
|
|
144
|
+
|
|
145
|
+
# Single database transaction
|
|
146
|
+
async with ctx_session() as session:
|
|
147
|
+
user = await User.objects.using(session).create(username="bob")
|
|
148
|
+
posts = await user.posts.using(session).all()
|
|
149
|
+
# Automatic commit on success, rollback on error
|
|
150
|
+
|
|
151
|
+
# Multi-database transactions
|
|
152
|
+
async with ctx_sessions("main", "analytics") as sessions:
|
|
153
|
+
user = await User.objects.using(sessions["main"]).create(username="alice")
|
|
154
|
+
await Log.objects.using(sessions["analytics"]).create(message="User created")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Lifecycle Hooks
|
|
158
|
+
|
|
159
|
+
Comprehensive signal system for database operations:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
class User(ObjectModel):
|
|
163
|
+
username: Column[str] = StringColumn(length=50)
|
|
164
|
+
|
|
165
|
+
async def before_save(self, context):
|
|
166
|
+
"""Called before any save operation"""
|
|
167
|
+
self.updated_at = datetime.now()
|
|
168
|
+
|
|
169
|
+
async def after_create(self, context):
|
|
170
|
+
"""Called only after creation"""
|
|
171
|
+
await self.send_welcome_email()
|
|
172
|
+
|
|
173
|
+
async def before_delete(self, context):
|
|
174
|
+
"""Called before deletion"""
|
|
175
|
+
await self.cleanup_related_data()
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## 🏗️ Architecture
|
|
179
|
+
|
|
180
|
+
SQLObjects is built on a solid foundation with clear architectural principles:
|
|
181
|
+
|
|
182
|
+
- **SQLAlchemy Core** - Maximum performance and control over SQL generation
|
|
183
|
+
- **Async-first** - Native async/await support throughout the library
|
|
184
|
+
- **Type safety** - Comprehensive type annotations and runtime validation
|
|
185
|
+
- **Modular design** - Clean separation of concerns and extensible architecture
|
|
186
|
+
|
|
187
|
+
## 📖 Documentation
|
|
188
|
+
|
|
189
|
+
### Feature Documentation
|
|
190
|
+
|
|
191
|
+
- [Database Setup](docs/features/01-database-setup.md) - Database configuration and connection management
|
|
192
|
+
- [Model Definition](docs/features/02-model-definition.md) - Model creation, fields, and validation
|
|
193
|
+
- [Querying Data](docs/features/03-querying-data.md) - Query building, filtering, and aggregation
|
|
194
|
+
- [CRUD Operations](docs/features/04-crud-operations.md) - Create, read, update, delete operations
|
|
195
|
+
- [Relationships](docs/features/05-relationships.md) - Model relationships and loading strategies
|
|
196
|
+
- [Validation & Signals](docs/features/06-validation-signals.md) - Data validation and lifecycle hooks
|
|
197
|
+
- [Performance Optimization](docs/features/07-performance-optimization.md) - Performance tuning and best practices
|
|
198
|
+
|
|
199
|
+
### Design Documentation
|
|
200
|
+
|
|
201
|
+
- [Core Architecture](docs/design/01-core-architecture.md) - System architecture and design principles
|
|
202
|
+
- [Data Operations](docs/design/02-data-operations.md) - Query execution and data processing
|
|
203
|
+
- [Field System](docs/design/03-field-system.md) - Field types and type system
|
|
204
|
+
- [Relationships](docs/design/04-relationships.md) - Relationship implementation details
|
|
205
|
+
- [Extensions](docs/design/05-extensions.md) - Extension points and customization
|
|
206
|
+
|
|
207
|
+
## 🔧 Advanced Features
|
|
208
|
+
|
|
209
|
+
### Multi-Database Support
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
from sqlobjects.database import init_dbs
|
|
213
|
+
|
|
214
|
+
# Configure multiple databases
|
|
215
|
+
main_db, analytics_db = await init_dbs({
|
|
216
|
+
"main": {"url": "postgresql+asyncpg://user:pass@localhost/main"},
|
|
217
|
+
"analytics": {"url": "sqlite+aiosqlite:///analytics.db"}
|
|
218
|
+
}, default="main")
|
|
219
|
+
|
|
220
|
+
# Use specific databases
|
|
221
|
+
user = await User.objects.using("analytics").create(username="analyst")
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Performance Optimization
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
# Memory-efficient iteration for large datasets
|
|
228
|
+
async for user in User.objects.iterator(chunk_size=1000):
|
|
229
|
+
await process_user(user)
|
|
230
|
+
|
|
231
|
+
# Cache control for performance
|
|
232
|
+
users = await User.objects.filter(User.is_active == True).all() # Uses cache
|
|
233
|
+
live_data = await User.objects.no_cache().filter(User.status == "online").all() # Skip cache
|
|
234
|
+
|
|
235
|
+
# Field-level performance optimization
|
|
236
|
+
class User(ObjectModel):
|
|
237
|
+
bio: Column[str] = column(type="text", deferred=True) # Lazy loading
|
|
238
|
+
profile_image: Column[bytes] = column(type="binary", deferred=True)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Advanced Querying
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
# Subqueries and complex conditions
|
|
245
|
+
avg_age = User.objects.aggregate(avg_age=func.avg(User.age)).subquery(query_type="scalar")
|
|
246
|
+
older_users = await User.objects.filter(User.age > avg_age).all()
|
|
247
|
+
|
|
248
|
+
# Manual joins and locking
|
|
249
|
+
posts = await Post.objects.join(
|
|
250
|
+
User.__table__,
|
|
251
|
+
Post.author_id == User.id
|
|
252
|
+
).select_for_update(nowait=True).all()
|
|
253
|
+
|
|
254
|
+
# Raw SQL when needed
|
|
255
|
+
users = await User.objects.raw(
|
|
256
|
+
"SELECT * FROM users WHERE age > :age",
|
|
257
|
+
{"age": 18}
|
|
258
|
+
)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## 🧪 Testing
|
|
262
|
+
|
|
263
|
+
SQLObjects includes comprehensive test coverage:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Run all tests
|
|
267
|
+
uv run pytest
|
|
268
|
+
|
|
269
|
+
# Run specific test categories
|
|
270
|
+
uv run pytest tests/unit/ # Unit tests
|
|
271
|
+
uv run pytest tests/integration/ # Integration tests
|
|
272
|
+
uv run pytest tests/performance/ # Performance tests
|
|
273
|
+
|
|
274
|
+
# Run with coverage
|
|
275
|
+
uv run pytest --cov=sqlobjects
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## 🤝 Contributing
|
|
279
|
+
|
|
280
|
+
We welcome contributions! Please see our development guidelines:
|
|
281
|
+
|
|
282
|
+
1. **Design-first approach** - All changes start with design analysis
|
|
283
|
+
2. **Type safety** - Maintain comprehensive type annotations
|
|
284
|
+
3. **Test coverage** - Include tests for all new functionality
|
|
285
|
+
4. **Documentation** - Update docs for any API changes
|
|
286
|
+
|
|
287
|
+
### Development Setup
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# Clone the repository
|
|
291
|
+
git clone https://github.com/XtraVisionsAI/sqlobjects.git
|
|
292
|
+
cd sqlobjects
|
|
293
|
+
|
|
294
|
+
# Install development dependencies
|
|
295
|
+
uv sync --group dev --group test
|
|
296
|
+
|
|
297
|
+
# Run pre-commit hooks
|
|
298
|
+
uv run pre-commit install
|
|
299
|
+
|
|
300
|
+
# Run tests
|
|
301
|
+
uv run pytest
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## 📋 Roadmap
|
|
305
|
+
|
|
306
|
+
See our [TODO.md](TODO.md) for planned features:
|
|
307
|
+
|
|
308
|
+
- **v2.0**: Database health checks, window functions, advanced bulk operations
|
|
309
|
+
- **v2.1**: Advanced cache management, query optimization tools
|
|
310
|
+
- **v2.2+**: CTE support, advanced SQL functions
|
|
311
|
+
|
|
312
|
+
## 📄 License
|
|
313
|
+
|
|
314
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
315
|
+
|
|
316
|
+
## 🙏 Acknowledgments
|
|
317
|
+
|
|
318
|
+
- Built on the excellent [SQLAlchemy](https://www.sqlalchemy.org/) library
|
|
319
|
+
- Inspired by [Django ORM](https://docs.djangoproject.com/en/stable/topics/db/) API design
|
|
320
|
+
- Thanks to all contributors and the Python async ecosystem
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
**SQLObjects** - Modern async ORM for Python 3.12+
|