@martinffx/atelier 1.4.0 → 3.0.0
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.
- package/CHANGELOG.md +38 -0
- package/README.md +95 -220
- package/agents/architect.md +6 -6
- package/agents/oracle.md +1 -1
- package/agents/{recon.md → sentinel.md} +3 -3
- package/dist/atelier.js +167 -26
- package/package.json +2 -1
- package/skills/atelier-orchestrator/SKILL.md +180 -0
- package/skills/atelier-setup/SKILL.md +80 -0
- package/skills/code-review/SKILL.md +2 -2
- package/skills/code-review/references/reviewers.md +3 -3
- package/skills/code-review/references/rq.md +9 -9
- package/skills/code-subagents/SKILL.md +44 -75
- package/skills/code-subagents/references/batch-reviewer-prompt.md +44 -0
- package/skills/code-subagents/references/implementor-prompt.md +10 -11
- package/skills/spec-brainstorm/SKILL.md +21 -16
- package/skills/spec-finish/SKILL.md +14 -14
- package/skills/spec-implement/SKILL.md +42 -42
- package/skills/spec-plan/SKILL.md +72 -26
- package/skills/spec-plan/references/plan_template.md +77 -0
- package/skills/code-subagents/references/code-quality-reviewer-prompt.md +0 -48
- package/skills/code-subagents/references/spec-reviewer-prompt.md +0 -62
- package/skills/python-architecture/SKILL.md +0 -148
- package/skills/python-architecture/references/data-modeling.md +0 -558
- package/skills/python-architecture/references/ddd.md +0 -569
- package/skills/python-architecture/references/functional-core.md +0 -337
- package/skills/python-build-tools/SKILL.md +0 -153
- package/skills/python-build-tools/references/basedpyright.md +0 -321
- package/skills/python-build-tools/references/ruff.md +0 -225
- package/skills/python-build-tools/references/uv.md +0 -257
- package/skills/python-fastapi/SKILL.md +0 -184
- package/skills/python-fastapi/references/api-design.md +0 -563
- package/skills/python-fastapi/references/dependencies.md +0 -479
- package/skills/python-fastapi/references/middleware.md +0 -475
- package/skills/python-fastapi/references/validation.md +0 -497
- package/skills/python-modern-python/SKILL.md +0 -201
- package/skills/python-modern-python/references/async.md +0 -76
- package/skills/python-modern-python/references/pattern-matching.md +0 -89
- package/skills/python-modern-python/references/typing.md +0 -96
- package/skills/python-monorepo/SKILL.md +0 -146
- package/skills/python-monorepo/references/docker.md +0 -515
- package/skills/python-monorepo/references/namespace-packages.md +0 -426
- package/skills/python-monorepo/references/workspace-config.md +0 -341
- package/skills/python-sqlalchemy/SKILL.md +0 -119
- package/skills/python-sqlalchemy/references/async.md +0 -51
- package/skills/python-sqlalchemy/references/models.md +0 -67
- package/skills/python-sqlalchemy/references/queries.md +0 -57
- package/skills/python-temporal/SKILL.md +0 -128
- package/skills/python-temporal/references/patterns.md +0 -87
- package/skills/python-temporal/references/testing.md +0 -54
- package/skills/python-testing/SKILL.md +0 -161
- package/skills/python-testing/references/boundaries.md +0 -449
- package/skills/python-testing/references/mocking.md +0 -449
- package/skills/python-testing/references/pytest.md +0 -524
- package/skills/spec-orchestrator/SKILL.md +0 -145
- package/skills/typescript-api-design/SKILL.md +0 -396
- package/skills/typescript-api-design/references/error-responses.md +0 -469
- package/skills/typescript-build-tools/SKILL.md +0 -447
- package/skills/typescript-build-tools/references/biome.md +0 -436
- package/skills/typescript-build-tools/references/bun.md +0 -432
- package/skills/typescript-build-tools/references/turborepo.md +0 -426
- package/skills/typescript-build-tools/references/vitest.md +0 -518
- package/skills/typescript-drizzle-orm/SKILL.md +0 -398
- package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
- package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
- package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
- package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
- package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
- package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
- package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
- package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
- package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
- package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
- package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
- package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
- package/skills/typescript-effect-ts/SKILL.md +0 -341
- package/skills/typescript-effect-ts/references/core.md +0 -412
- package/skills/typescript-effect-ts/references/error-handling.md +0 -468
- package/skills/typescript-effect-ts/references/resources.md +0 -476
- package/skills/typescript-effect-ts/references/schema.md +0 -536
- package/skills/typescript-effect-ts/references/services.md +0 -461
- package/skills/typescript-fastify/SKILL.md +0 -405
- package/skills/typescript-fastify/references/plugins.md +0 -329
- package/skills/typescript-fastify/references/typeid.md +0 -315
- package/skills/typescript-functional-patterns/SKILL.md +0 -402
- package/skills/typescript-functional-patterns/references/adts.md +0 -497
- package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
- package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
- package/skills/typescript-functional-patterns/references/option-result.md +0 -585
- package/skills/typescript-testing/SKILL.md +0 -353
- package/skills/typescript-testing/references/mocking.md +0 -675
- package/skills/typescript-testing/references/msw.md +0 -852
- package/skills/typescript-testing/references/snapshot-testing.md +0 -774
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
# Workspace Configuration Details
|
|
2
|
-
|
|
3
|
-
Comprehensive pyproject.toml patterns for Python monorepos using uv workspaces.
|
|
4
|
-
|
|
5
|
-
## Root Workspace Configuration
|
|
6
|
-
|
|
7
|
-
**pyproject.toml** at repository root defines workspace structure and shared tooling:
|
|
8
|
-
|
|
9
|
-
```toml
|
|
10
|
-
[project]
|
|
11
|
-
name = "my-monorepo"
|
|
12
|
-
version = "0.1.0"
|
|
13
|
-
requires-python = ">=3.12"
|
|
14
|
-
|
|
15
|
-
[tool.uv.workspace]
|
|
16
|
-
members = [
|
|
17
|
-
"apps/*",
|
|
18
|
-
"packages/*"
|
|
19
|
-
]
|
|
20
|
-
|
|
21
|
-
[tool.uv]
|
|
22
|
-
dev-dependencies = [
|
|
23
|
-
"pytest>=8.0.0",
|
|
24
|
-
"ruff>=0.8.0",
|
|
25
|
-
"basedpyright>=1.0.0",
|
|
26
|
-
]
|
|
27
|
-
|
|
28
|
-
[tool.ruff]
|
|
29
|
-
line-length = 100
|
|
30
|
-
target-version = "py312"
|
|
31
|
-
|
|
32
|
-
[tool.ruff.lint]
|
|
33
|
-
select = ["E", "F", "I", "N", "UP", "RUF"]
|
|
34
|
-
|
|
35
|
-
[tool.basedpyright]
|
|
36
|
-
typeCheckingMode = "strict"
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
**Key sections:**
|
|
40
|
-
- `[project]`: Workspace metadata
|
|
41
|
-
- `[tool.uv.workspace]`: Member glob patterns
|
|
42
|
-
- `[tool.uv]`: Shared dev dependencies (pytest, linting, type-checking)
|
|
43
|
-
- Tool configurations (ruff, basedpyright) shared across all packages
|
|
44
|
-
|
|
45
|
-
## Package Configuration
|
|
46
|
-
|
|
47
|
-
Each workspace member has its own `pyproject.toml` with package-specific settings.
|
|
48
|
-
|
|
49
|
-
### Shared Library (packages/core)
|
|
50
|
-
|
|
51
|
-
```toml
|
|
52
|
-
[project]
|
|
53
|
-
name = "my-core"
|
|
54
|
-
version = "0.1.0"
|
|
55
|
-
requires-python = ">=3.12"
|
|
56
|
-
description = "Shared core library"
|
|
57
|
-
dependencies = [
|
|
58
|
-
"pydantic>=2.0.0",
|
|
59
|
-
]
|
|
60
|
-
|
|
61
|
-
[build-system]
|
|
62
|
-
requires = ["hatchling"]
|
|
63
|
-
build-backend = "hatchling.build"
|
|
64
|
-
|
|
65
|
-
[tool.hatch.build.targets.wheel]
|
|
66
|
-
packages = ["src/my_core"]
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Package with Dependencies (packages/utils)
|
|
70
|
-
|
|
71
|
-
```toml
|
|
72
|
-
[project]
|
|
73
|
-
name = "my-utils"
|
|
74
|
-
version = "0.1.0"
|
|
75
|
-
requires-python = ">=3.12"
|
|
76
|
-
dependencies = [
|
|
77
|
-
"my-core", # Reference workspace package by distribution name
|
|
78
|
-
"python-dateutil>=2.8.0",
|
|
79
|
-
]
|
|
80
|
-
|
|
81
|
-
[build-system]
|
|
82
|
-
requires = ["hatchling"]
|
|
83
|
-
build-backend = "hatchling.build"
|
|
84
|
-
|
|
85
|
-
[tool.hatch.build.targets.wheel]
|
|
86
|
-
packages = ["src/my_utils"]
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Application (apps/api)
|
|
90
|
-
|
|
91
|
-
```toml
|
|
92
|
-
[project]
|
|
93
|
-
name = "my-api"
|
|
94
|
-
version = "0.1.0"
|
|
95
|
-
requires-python = ">=3.12"
|
|
96
|
-
dependencies = [
|
|
97
|
-
"fastapi>=0.100.0",
|
|
98
|
-
"uvicorn>=0.20.0",
|
|
99
|
-
"my-core", # Workspace package
|
|
100
|
-
"my-utils", # Workspace package
|
|
101
|
-
]
|
|
102
|
-
|
|
103
|
-
[project.scripts]
|
|
104
|
-
api = "my_api.main:run"
|
|
105
|
-
|
|
106
|
-
[build-system]
|
|
107
|
-
requires = ["hatchling"]
|
|
108
|
-
build-backend = "hatchling.build"
|
|
109
|
-
|
|
110
|
-
[tool.hatch.build.targets.wheel]
|
|
111
|
-
packages = ["src/my_api"]
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Workspace Member Patterns
|
|
115
|
-
|
|
116
|
-
### Glob Pattern Variations
|
|
117
|
-
|
|
118
|
-
```toml
|
|
119
|
-
# Include all apps and packages
|
|
120
|
-
[tool.uv.workspace]
|
|
121
|
-
members = ["apps/*", "packages/*"]
|
|
122
|
-
|
|
123
|
-
# Include specific subdirectories
|
|
124
|
-
[tool.uv.workspace]
|
|
125
|
-
members = [
|
|
126
|
-
"apps/api",
|
|
127
|
-
"apps/worker",
|
|
128
|
-
"packages/core",
|
|
129
|
-
"packages/utils",
|
|
130
|
-
]
|
|
131
|
-
|
|
132
|
-
# Namespace package pattern
|
|
133
|
-
[tool.uv.workspace]
|
|
134
|
-
members = ["packages/acme-*"] # All packages starting with acme-
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Nested Structure
|
|
138
|
-
|
|
139
|
-
```toml
|
|
140
|
-
# For deeply nested layouts
|
|
141
|
-
[tool.uv.workspace]
|
|
142
|
-
members = [
|
|
143
|
-
"services/*/service",
|
|
144
|
-
"libs/*/library",
|
|
145
|
-
]
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## Shared Tool Configuration
|
|
149
|
-
|
|
150
|
-
### Pytest Configuration
|
|
151
|
-
|
|
152
|
-
```toml
|
|
153
|
-
[tool.pytest.ini_options]
|
|
154
|
-
testpaths = ["packages", "apps"]
|
|
155
|
-
python_files = ["test_*.py", "*_test.py"]
|
|
156
|
-
python_classes = ["Test*"]
|
|
157
|
-
python_functions = ["test_*"]
|
|
158
|
-
addopts = "-v --strict-markers"
|
|
159
|
-
markers = [
|
|
160
|
-
"unit: unit tests",
|
|
161
|
-
"integration: integration tests",
|
|
162
|
-
"slow: slow tests",
|
|
163
|
-
]
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Ruff Configuration
|
|
167
|
-
|
|
168
|
-
```toml
|
|
169
|
-
[tool.ruff]
|
|
170
|
-
line-length = 100
|
|
171
|
-
target-version = "py312"
|
|
172
|
-
|
|
173
|
-
[tool.ruff.lint]
|
|
174
|
-
select = [
|
|
175
|
-
"E", # Errors
|
|
176
|
-
"F", # PyFlakes
|
|
177
|
-
"I", # isort
|
|
178
|
-
"N", # pep8-naming
|
|
179
|
-
"UP", # pyupgrade
|
|
180
|
-
"RUF", # Ruff-specific
|
|
181
|
-
]
|
|
182
|
-
ignore = ["E501"] # Line too long (handled by formatter)
|
|
183
|
-
|
|
184
|
-
[tool.ruff.lint.isort]
|
|
185
|
-
known-first-party = ["my_core", "my_utils", "my_api"]
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Type Checking (basedpyright)
|
|
189
|
-
|
|
190
|
-
```toml
|
|
191
|
-
[tool.basedpyright]
|
|
192
|
-
typeCheckingMode = "strict"
|
|
193
|
-
include = ["packages/*/src", "apps/*/src"]
|
|
194
|
-
exclude = ["**/tests", "**/__pycache__"]
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## uv Commands
|
|
198
|
-
|
|
199
|
-
### Install and Sync
|
|
200
|
-
|
|
201
|
-
```bash
|
|
202
|
-
# Install all workspace dependencies with lock
|
|
203
|
-
uv sync
|
|
204
|
-
|
|
205
|
-
# Sync without installing
|
|
206
|
-
uv lock
|
|
207
|
-
|
|
208
|
-
# Upgrade all dependencies
|
|
209
|
-
uv lock --upgrade
|
|
210
|
-
|
|
211
|
-
# Upgrade specific package
|
|
212
|
-
uv lock --upgrade-package fastapi
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### Add Dependencies
|
|
216
|
-
|
|
217
|
-
```bash
|
|
218
|
-
# Add to root dev dependencies
|
|
219
|
-
uv add --dev pytest
|
|
220
|
-
|
|
221
|
-
# Add to specific workspace package
|
|
222
|
-
uv add fastapi --package my-api
|
|
223
|
-
|
|
224
|
-
# Add workspace package as dependency
|
|
225
|
-
uv add my-core --package my-utils
|
|
226
|
-
|
|
227
|
-
# Add with specific version
|
|
228
|
-
uv add "requests>=2.28.0" --package my-api
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Run Commands
|
|
232
|
-
|
|
233
|
-
```bash
|
|
234
|
-
# Run in root environment
|
|
235
|
-
uv run pytest
|
|
236
|
-
|
|
237
|
-
# Run in specific package
|
|
238
|
-
uv run --package my-api pytest
|
|
239
|
-
|
|
240
|
-
# Run package entrypoint
|
|
241
|
-
uv run --package my-api api
|
|
242
|
-
|
|
243
|
-
# Run Python module
|
|
244
|
-
uv run python -m my_api.main
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
## Multi-Platform Requirements
|
|
248
|
-
|
|
249
|
-
```toml
|
|
250
|
-
[project]
|
|
251
|
-
dependencies = [
|
|
252
|
-
"requests",
|
|
253
|
-
"pywin32>=300; sys_platform == 'win32'", # Windows only
|
|
254
|
-
"fcntl; sys_platform != 'win32'", # Unix only
|
|
255
|
-
]
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
## Optional Dependencies
|
|
259
|
-
|
|
260
|
-
```toml
|
|
261
|
-
[project]
|
|
262
|
-
name = "my-api"
|
|
263
|
-
dependencies = ["fastapi"]
|
|
264
|
-
|
|
265
|
-
[project.optional-dependencies]
|
|
266
|
-
db = ["sqlalchemy>=2.0.0", "alembic>=1.10.0"]
|
|
267
|
-
cache = ["redis>=4.0.0", "pydantic-settings>=2.0.0"]
|
|
268
|
-
dev = ["pytest-cov>=4.0.0"]
|
|
269
|
-
|
|
270
|
-
# Install with extras
|
|
271
|
-
# uv sync --extra db --extra cache
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
## Version Pinning Strategies
|
|
275
|
-
|
|
276
|
-
### Loose Versioning (Recommended for libs)
|
|
277
|
-
|
|
278
|
-
```toml
|
|
279
|
-
dependencies = [
|
|
280
|
-
"pydantic>=2.0.0", # At least 2.0.0
|
|
281
|
-
"requests<3", # Before 3.0.0
|
|
282
|
-
]
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### Strict Versioning (For production)
|
|
286
|
-
|
|
287
|
-
```toml
|
|
288
|
-
dependencies = [
|
|
289
|
-
"pydantic==2.5.0", # Exact version
|
|
290
|
-
]
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
### Compatible Release
|
|
294
|
-
|
|
295
|
-
```toml
|
|
296
|
-
dependencies = [
|
|
297
|
-
"pydantic~=2.5.0", # >= 2.5.0, < 2.6.0
|
|
298
|
-
]
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
## Workspace with Conditional Packages
|
|
302
|
-
|
|
303
|
-
```toml
|
|
304
|
-
[tool.uv.workspace]
|
|
305
|
-
members = [
|
|
306
|
-
"packages/core",
|
|
307
|
-
"packages/postgres", # Optional database
|
|
308
|
-
"packages/redis", # Optional cache
|
|
309
|
-
"apps/*",
|
|
310
|
-
]
|
|
311
|
-
|
|
312
|
-
# Then only include in dependencies when needed
|
|
313
|
-
# my-api can depend on my-postgres when database is needed
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
## Dependency Management Best Practices
|
|
317
|
-
|
|
318
|
-
1. **Keep root dependencies minimal** - Only dev tools that apply to all packages
|
|
319
|
-
2. **Version independently** - Each package manages its own versions
|
|
320
|
-
3. **Single lock file** - One `uv.lock` at root for reproducibility
|
|
321
|
-
4. **Workspace references** - Use distribution names (my-core) not paths
|
|
322
|
-
5. **Clear boundaries** - Apps depend on packages, not vice versa
|
|
323
|
-
|
|
324
|
-
## Summary
|
|
325
|
-
|
|
326
|
-
**Root config:**
|
|
327
|
-
- Defines workspace members via glob patterns
|
|
328
|
-
- Specifies shared dev dependencies
|
|
329
|
-
- Centralizes tool configuration (ruff, basedpyright, pytest)
|
|
330
|
-
|
|
331
|
-
**Package config:**
|
|
332
|
-
- Independent versioning
|
|
333
|
-
- Package-specific dependencies
|
|
334
|
-
- Reference other workspace packages by name
|
|
335
|
-
|
|
336
|
-
**Key commands:**
|
|
337
|
-
- `uv sync` - Install all dependencies
|
|
338
|
-
- `uv add <pkg> --package <name>` - Add to specific package
|
|
339
|
-
- `uv lock --upgrade` - Update dependencies
|
|
340
|
-
|
|
341
|
-
See `/SKILL.md` for structure overview and references for Docker and namespace packages.
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: python-sqlalchemy
|
|
3
|
-
description: SQLAlchemy ORM patterns for Python database access. Use when defining models, writing queries, implementing upserts, working with JSON columns, or managing database sessions.
|
|
4
|
-
user-invocable: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# SQLAlchemy ORM Patterns
|
|
8
|
-
|
|
9
|
-
Modern SQLAlchemy 2.0+ patterns for database access in Python applications.
|
|
10
|
-
|
|
11
|
-
## Model Definition
|
|
12
|
-
|
|
13
|
-
```python
|
|
14
|
-
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
15
|
-
from sqlalchemy import String
|
|
16
|
-
from uuid import UUID
|
|
17
|
-
from decimal import Decimal
|
|
18
|
-
|
|
19
|
-
class Base(DeclarativeBase):
|
|
20
|
-
pass
|
|
21
|
-
|
|
22
|
-
class ProductModel(Base):
|
|
23
|
-
__tablename__ = "products"
|
|
24
|
-
|
|
25
|
-
id: Mapped[UUID] = mapped_column(primary_key=True)
|
|
26
|
-
name: Mapped[str] = mapped_column(String(100))
|
|
27
|
-
price: Mapped[Decimal]
|
|
28
|
-
in_stock: Mapped[bool] = mapped_column(default=True)
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Session Management
|
|
32
|
-
|
|
33
|
-
```python
|
|
34
|
-
from sqlalchemy import create_engine
|
|
35
|
-
from sqlalchemy.orm import sessionmaker
|
|
36
|
-
|
|
37
|
-
engine = create_engine("postgresql://user:pass@localhost/db")
|
|
38
|
-
SessionLocal = sessionmaker(bind=engine)
|
|
39
|
-
|
|
40
|
-
def get_db():
|
|
41
|
-
db = SessionLocal()
|
|
42
|
-
try:
|
|
43
|
-
yield db
|
|
44
|
-
finally:
|
|
45
|
-
db.close()
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Query Patterns
|
|
49
|
-
|
|
50
|
-
```python
|
|
51
|
-
# Select
|
|
52
|
-
stmt = select(ProductModel).where(ProductModel.price > 100)
|
|
53
|
-
products = session.execute(stmt).scalars().all()
|
|
54
|
-
|
|
55
|
-
# Filter
|
|
56
|
-
products = session.query(ProductModel).filter(ProductModel.in_stock == True).all()
|
|
57
|
-
|
|
58
|
-
# Get by ID
|
|
59
|
-
product = session.get(ProductModel, product_id)
|
|
60
|
-
|
|
61
|
-
# Count
|
|
62
|
-
count = session.query(ProductModel).count()
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Upsert
|
|
66
|
-
|
|
67
|
-
```python
|
|
68
|
-
from sqlalchemy.dialects.postgresql import insert
|
|
69
|
-
|
|
70
|
-
stmt = insert(ProductModel).values(
|
|
71
|
-
id=product_id,
|
|
72
|
-
name="Widget",
|
|
73
|
-
price=9.99,
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
# On conflict, update
|
|
77
|
-
stmt = stmt.on_conflict_do_update(
|
|
78
|
-
index_elements=["id"],
|
|
79
|
-
set_={"name": stmt.excluded.name, "price": stmt.excluded.price},
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
session.execute(stmt)
|
|
83
|
-
session.commit()
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Relationships
|
|
87
|
-
|
|
88
|
-
```python
|
|
89
|
-
from sqlalchemy.orm import relationship
|
|
90
|
-
|
|
91
|
-
class UserModel(Base):
|
|
92
|
-
__tablename__ = "users"
|
|
93
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
94
|
-
orders: Mapped[list["OrderModel"]] = relationship(back_populates="user")
|
|
95
|
-
|
|
96
|
-
class OrderModel(Base):
|
|
97
|
-
__tablename__ = "orders"
|
|
98
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
99
|
-
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
|
|
100
|
-
user: Mapped["UserModel"] = relationship(back_populates="orders")
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## JSON Columns
|
|
104
|
-
|
|
105
|
-
```python
|
|
106
|
-
from sqlalchemy import JSON
|
|
107
|
-
|
|
108
|
-
class ConfigModel(Base):
|
|
109
|
-
__tablename__ = "configs"
|
|
110
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
111
|
-
settings: Mapped[dict] = mapped_column(JSON)
|
|
112
|
-
|
|
113
|
-
# Query JSON field
|
|
114
|
-
configs = session.query(ConfigModel).filter(
|
|
115
|
-
ConfigModel.settings["theme"] == "dark"
|
|
116
|
-
).all()
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
See references/ for model patterns, query optimization, and async SQLAlchemy.
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Async SQLAlchemy
|
|
2
|
-
|
|
3
|
-
## Setup
|
|
4
|
-
|
|
5
|
-
```python
|
|
6
|
-
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
|
7
|
-
from sqlalchemy.ext.asyncio import async_sessionmaker
|
|
8
|
-
|
|
9
|
-
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
|
|
10
|
-
AsyncSessionLocal = async_sessionmaker(engine, class_=AsyncSession)
|
|
11
|
-
|
|
12
|
-
async def get_db():
|
|
13
|
-
async with AsyncSessionLocal() as session:
|
|
14
|
-
yield session
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Async Queries
|
|
18
|
-
|
|
19
|
-
```python
|
|
20
|
-
from sqlalchemy import select
|
|
21
|
-
|
|
22
|
-
async def get_users():
|
|
23
|
-
async with AsyncSessionLocal() as session:
|
|
24
|
-
stmt = select(User).where(User.is_active == True)
|
|
25
|
-
result = await session.execute(stmt)
|
|
26
|
-
return result.scalars().all()
|
|
27
|
-
|
|
28
|
-
async def create_user(user_data):
|
|
29
|
-
async with AsyncSessionLocal() as session:
|
|
30
|
-
user = User(**user_data)
|
|
31
|
-
session.add(user)
|
|
32
|
-
await session.commit()
|
|
33
|
-
await session.refresh(user)
|
|
34
|
-
return user
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## FastAPI Integration
|
|
38
|
-
|
|
39
|
-
```python
|
|
40
|
-
from fastapi import Depends
|
|
41
|
-
|
|
42
|
-
async def get_db():
|
|
43
|
-
async with AsyncSessionLocal() as session:
|
|
44
|
-
yield session
|
|
45
|
-
|
|
46
|
-
@app.get("/users")
|
|
47
|
-
async def list_users(db: AsyncSession = Depends(get_db)):
|
|
48
|
-
stmt = select(User)
|
|
49
|
-
result = await db.execute(stmt)
|
|
50
|
-
return result.scalars().all()
|
|
51
|
-
```
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# SQLAlchemy Models
|
|
2
|
-
|
|
3
|
-
## Declarative Models (2.0 Style)
|
|
4
|
-
|
|
5
|
-
```python
|
|
6
|
-
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
7
|
-
from sqlalchemy import String, ForeignKey
|
|
8
|
-
from datetime import datetime
|
|
9
|
-
from uuid import UUID
|
|
10
|
-
|
|
11
|
-
class Base(DeclarativeBase):
|
|
12
|
-
pass
|
|
13
|
-
|
|
14
|
-
class User(Base):
|
|
15
|
-
__tablename__ = "users"
|
|
16
|
-
|
|
17
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
18
|
-
email: Mapped[str] = mapped_column(String(255), unique=True)
|
|
19
|
-
name: Mapped[str] = mapped_column(String(100))
|
|
20
|
-
created_at: Mapped[datetime] = mapped_column(default=datetime.now)
|
|
21
|
-
is_active: Mapped[bool] = mapped_column(default=True)
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Relationships
|
|
25
|
-
|
|
26
|
-
```python
|
|
27
|
-
from sqlalchemy.orm import relationship
|
|
28
|
-
|
|
29
|
-
class User(Base):
|
|
30
|
-
__tablename__ = "users"
|
|
31
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
32
|
-
orders: Mapped[list["Order"]] = relationship(back_populates="user")
|
|
33
|
-
|
|
34
|
-
class Order(Base):
|
|
35
|
-
__tablename__ = "orders"
|
|
36
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
37
|
-
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
|
|
38
|
-
user: Mapped["User"] = relationship(back_populates="orders")
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Indexes
|
|
42
|
-
|
|
43
|
-
```python
|
|
44
|
-
from sqlalchemy import Index
|
|
45
|
-
|
|
46
|
-
class Product(Base):
|
|
47
|
-
__tablename__ = "products"
|
|
48
|
-
|
|
49
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
50
|
-
category: Mapped[str]
|
|
51
|
-
price: Mapped[Decimal]
|
|
52
|
-
|
|
53
|
-
__table_args__ = (
|
|
54
|
-
Index("idx_category_price", "category", "price"),
|
|
55
|
-
)
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## JSON Columns
|
|
59
|
-
|
|
60
|
-
```python
|
|
61
|
-
from sqlalchemy import JSON
|
|
62
|
-
|
|
63
|
-
class Config(Base):
|
|
64
|
-
__tablename__ = "configs"
|
|
65
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
66
|
-
settings: Mapped[dict] = mapped_column(JSON)
|
|
67
|
-
```
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# SQLAlchemy Queries
|
|
2
|
-
|
|
3
|
-
## Select Queries (2.0 Style)
|
|
4
|
-
|
|
5
|
-
```python
|
|
6
|
-
from sqlalchemy import select
|
|
7
|
-
|
|
8
|
-
# All records
|
|
9
|
-
stmt = select(User)
|
|
10
|
-
users = session.execute(stmt).scalars().all()
|
|
11
|
-
|
|
12
|
-
# With filter
|
|
13
|
-
stmt = select(User).where(User.is_active == True)
|
|
14
|
-
users = session.execute(stmt).scalars().all()
|
|
15
|
-
|
|
16
|
-
# Get one
|
|
17
|
-
stmt = select(User).where(User.id == 1)
|
|
18
|
-
user = session.execute(stmt).scalar_one()
|
|
19
|
-
|
|
20
|
-
# Get by ID
|
|
21
|
-
user = session.get(User, 1)
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Joins
|
|
25
|
-
|
|
26
|
-
```python
|
|
27
|
-
stmt = select(User, Order).join(Order, User.id == Order.user_id)
|
|
28
|
-
results = session.execute(stmt).all()
|
|
29
|
-
|
|
30
|
-
# With filter
|
|
31
|
-
stmt = select(User).join(User.orders).where(Order.total > 100)
|
|
32
|
-
users = session.execute(stmt).scalars().all()
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Aggregation
|
|
36
|
-
|
|
37
|
-
```python
|
|
38
|
-
from sqlalchemy import func
|
|
39
|
-
|
|
40
|
-
# Count
|
|
41
|
-
count = session.query(User).count()
|
|
42
|
-
|
|
43
|
-
# Sum
|
|
44
|
-
total = session.query(func.sum(Order.total)).scalar()
|
|
45
|
-
|
|
46
|
-
# Group by
|
|
47
|
-
stmt = select(User.id, func.count(Order.id)).join(Order).group_by(User.id)
|
|
48
|
-
results = session.execute(stmt).all()
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Pagination
|
|
52
|
-
|
|
53
|
-
```python
|
|
54
|
-
# Offset/limit
|
|
55
|
-
stmt = select(User).offset(skip).limit(limit)
|
|
56
|
-
users = session.execute(stmt).scalars().all()
|
|
57
|
-
```
|