# ddd_domain Database-driven application using [half-orm](https://github.com/half-orm/half-orm) with [half-orm-dev](https://github.com/half-orm/half-orm-dev) workflow. **Database:** `ddd_domain` **Generated with:** half-orm-dev==1.0.0-a32 --- ## 🚀 Quick Start ### Prerequisites ```bash # Install half-orm-dev (includes half-orm) # IMPORTANT: Install the version specified in .hop/config. # Replace by the value of hop_version. pip install half-orm-dev== ``` **Version requirement:** This project requires `half-orm-dev >= 1.0.0-a32` ### Clone This Project ```bash # Clone project with automatic database setup (use git_origin in .hop/config) half_orm dev clone ``` This will: - Clone the repository and checkout `ho-prod` branch - Configure database connection in `/etc/half_orm/ddd_domain` or `${HALFORM_CONF_DIR}/ddd_domain` - Restore production schema from `.hop/model/schema.sql` - Generate Python ORM classes in `ddd_domain/` directory --- ## 📖 Development Workflow This project uses **half-orm-dev** for database versioning and patch management. ### 1. Create a Release ```bash # Create new minor release (e.g., 0.17.0) half_orm dev release create minor # Creates ho-release/0.17.0 branch # Creates .hop/releases/0.17.0-patches.toml ``` ### 2. Create a Patch # Create patch (auto-added as candidate) half_orm dev patch create - # Example: Create user authentication patch half_orm dev patch create 456-user-auth # Creates ho-patch/456-user-auth branch # Creates Patches/456-user-auth/ directory ``` ### 3. Develop Your Changes ```bash # Add SQL migration echo "CREATE TABLE users (id SERIAL PRIMARY KEY, username TEXT);" > Patches/456-user-auth/1-create-users.sql # Add Python migration (optional) cat > Patches/456-user-auth/2-seed-data.py << 'EOF' from ddd_domain.public.users import Users def apply(model): Users(username='admin').ho_insert() EOF # Apply patch to test database half_orm dev patch apply # Generated ORM classes available in ddd_domain/ from ddd_domain.public.users import Users user = Users(username='john').ho_insert() ``` ### 4. Test Your Changes ```bash # Run tests (pytest must be configured) pytest tests/ # half-orm-dev validates: # - Patch SQL syntax # - Patch idempotency (can be applied twice) # - Test suite passes with full release context ``` ### 5. Merge Patch into Release ```bash # Merge patch (automatic validation + tests) half_orm dev patch merge # What happens: # 1. Creates temp validation branch # 2. Applies ALL staged patches + your patch # 3. Runs pytest tests/ # 4. If tests pass → merges into ho-release/X.Y.Z # 5. Changes patch status to "staged" in TOML # 6. Deletes patch branch ``` ### 6. Promote Release ```bash # Stage → RC (first release candidate) half_orm dev release promote rc # Creates .hop/releases/0.17.0-rc1.txt snapshot # Tags ho-release-0.17.0-rc1 # RC → Production (after validation) half_orm dev release promote prod # Merges into ho-prod branch # Creates .hop/releases/0.17.0.txt # Tags production-0.17.0 # Generates .hop/model/schema-0.17.0.sql ``` --- ## 🔧 Common Commands ### Status & Information ```bash half_orm dev check # Show repository state ``` ### Patch Management ```bash half_orm dev patch create # create a new patch for release half_orm dev patch apply # Apply patch to dev database half_orm dev patch merge # Integrate patch into release ``` ### Release Management ```bash half_orm dev release create # Create release (patch/minor/major) half_orm dev release promote rc # Stage → RC half_orm dev release promote prod # RC → Production ``` ### Production Deployment ```bash # On production server half_orm dev update # Check available releases half_orm dev upgrade # Deploy specific version ``` --- ## 📁 Project Structure ``` ddd_domain/ ├── .hop/ # half-orm-dev metadata │ ├── config # Repository configuration │ ├── model/ # Database schemas and data │ │ ├── schema.sql # Current production schema (symlink) │ │ ├── schema-X.Y.Z.sql # Versioned schemas │ │ ├── metadata-X.Y.Z.sql # half_orm_meta data dumps │ │ └── data-X.Y.Z.sql # Reference data from @HOP:data patches │ └── releases/ # Release tracking files │ ├── X.Y.Z-patches.toml # Development releases (mutable) │ ├── X.Y.Z-rcN.txt # Release candidates (immutable) │ └── X.Y.Z.txt # Production releases (immutable) ├── Patches/ # Patch directories │ └── -/ # Individual patch files │ ├── *.sql # SQL migrations (numbered) │ └── *.py # Python migrations (optional) ├── ddd_domain/ # Generated ORM package │ └── / # schema classes └── tests/ # Test suite (pytest) ``` --- ## 🌿 Git Branch Structure - **`ho-prod`**: Production branch (stable, source of truth) - **`ho-release/X.Y.Z`**: Release integration branches (temporary) - **`ho-patch/ID`**: Patch development branches (temporary) All development happens on patch branches, merged into release branches, then promoted to production. --- ## 💾 Data Persistence (@HOP:data) For reference data that must be loaded with every database installation (lookup tables, default roles, etc.), use the `@HOP:data` annotation: ```sql -- @HOP:data -- This file will be included in model/data-X.Y.Z.sql INSERT INTO roles (name, description) VALUES ('admin', 'Administrator') ON CONFLICT (name) DO NOTHING; INSERT INTO permissions (name) VALUES ('read'), ('write'), ('delete') ON CONFLICT DO NOTHING; ``` ### How it works 1. **In patches**: SQL files starting with `-- @HOP:data` contain reference data 2. **Production promote**: All `@HOP:data` files are consolidated into `model/data-X.Y.Z.sql` 3. **Clone/Restore**: Data files are loaded automatically after schema restoration 4. **Production upgrade**: Data is inserted via normal patch application (no special handling) ### Best practices - Use `ON CONFLICT DO NOTHING` or `ON CONFLICT DO UPDATE` for idempotency - Keep data files small and focused (one concern per file) - Number your SQL files to control execution order: `01_roles.sql`, `02_permissions.sql` - Only use for **reference data**, not user-generated data --- ## ⚡ Async Usage The generated package supports both synchronous and asynchronous access to the database. ### Sync ```python from ddd_domain.public.users import Users user = Users(username='john').ho_get() users = list(Users(is_active=True).ho_select()) ``` ### Async ```python import asyncio from ddd_domain import aconnect, adisconnect from ddd_domain.public.users import Users async def main(): await aconnect() try: user = await Users(username='john').ho_aget() users = await Users(is_active=True).ho_aselect() finally: await adisconnect() asyncio.run(main()) ``` ### REST API (FastAPI) ```python from contextlib import asynccontextmanager from fastapi import FastAPI import ddd_domain @asynccontextmanager async def lifespan(app: FastAPI): await ddd_domain.aconnect() yield await ddd_domain.adisconnect() app = FastAPI(lifespan=lifespan) ``` The async connection pool is established automatically during tests via the `_async_pool` fixture in `tests/conftest.py`. --- ## 📚 Documentation - **half-orm-dev**: https://github.com/half-orm/half-orm-dev - **half-orm**: https://github.com/half-orm/half-orm - **Workflow guide**: https://github.com/half-orm/half-orm-dev#readme --- ## 🆘 Getting Help ```bash half_orm dev --help # General help half_orm dev patch --help # Patch commands half_orm dev release --help # Release commands ``` --- ## ⚠️ Important Notes 1. **Always work on patch branches** - Never commit directly to ho-prod or ho-release 2. **Test before merging** - `patch merge` runs tests automatically 3. **Sequential releases** - Only the smallest version in preparation can be promoted 4. **Idempotent patches** - SQL must be replayable (use `IF NOT EXISTS`, etc.) 5. **Production schema** - `.hop/model/schema.sql` is the source of truth --- Generated by half-orm-dev 1.0.0-a32