Stage 5: Complete SQLAlchemy 2.0 Migration - Final Stage#319
Merged
Conversation
Migrated 4 core files with 15 query patterns: - config_loader.py: 4 patterns (tenant lookups, subdomain/vhost resolution) - auth_utils.py: 5 patterns (principal/tenant auth lookups) - strategy.py: 5 patterns (strategy CRUD, simulation state management) - audit_logger.py: 2 patterns (tenant name lookups for notifications) All patterns converted from session.query() to select() + scalars(). Includes delete() pattern in strategy.py for reset() function. Related to PR #307 - SQLAlchemy 2.0 migration initiative. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Migrated database.py with 1 count pattern: - Converted session.query(Tenant).count() to select(func.count()).select_from(Tenant) - Used scalar() instead of execute() for count queries Total core files migrated: 5 files, 16 patterns converted. Related to PR #307 - SQLAlchemy 2.0 migration initiative. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…chemy 2.0 Migrated 2 service files with 2 query patterns: - format_metrics_service.py: 1 pattern (upsert query for metrics) - dynamic_pricing_service.py: 1 pattern (query with chained filters) Converted query().filter() to select().where() with scalars().all()/first(). Related to PR #307 - SQLAlchemy 2.0 migration initiative. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Migrated push_notification_service.py with 5 query patterns: - Converted all .query() calls to select() + scalars() - Patterns include: filter_by, filter with and_(), and in_() clauses - Fixed import order (ruff) All query patterns now use SQLAlchemy 2.0 style with explicit stmt variables. Related to PR #307 - SQLAlchemy 2.0 migration initiative. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…docs in database_session
Converted all `.query()` patterns in: - src/services/gam_inventory_service.py (17 patterns) - src/services/gam_orders_service.py (7 patterns) Changes: - Added `select`, `delete`, `update` imports - Converted `.query(Model)` → `stmt = select(Model)` - Converted `.filter()` → `.where()` - Converted `.all()/.first()` → `session.scalars(stmt).all()/.first()` - Converted `.update()` → `update(Model).values()` - Converted `.delete()` → `delete(Model).where()` - Converted `.count()` → `session.scalar(select(func.count()))` - Maintained readable formatting with proper variable names All conversions follow SQLAlchemy 2.0 best practices.
Converted all `.query()` patterns in: - src/adapters/google_ad_manager.py (1 pattern) - src/adapters/mock_ad_server.py (1 pattern) - src/adapters/xandr.py (1 pattern) - src/adapters/gam_reporting_api.py (8 patterns) - src/adapters/gam/managers/sync.py (6 patterns) - src/adapters/gam/managers/workflow.py (1 pattern) Changes: - Added `select` imports (and `func` where needed for count operations) - Converted `.query(Model)` → `stmt = select(Model)` - Converted `.filter_by()` → `.filter_by()` (still supported in select) - Converted `.where()` for more complex filters - Converted `.all()/.first()` → `session.scalars(stmt).all()/.first()` - Converted `.count()` → `session.scalar(select(func.count()).select_from(Model).where(...))` - Used `replace_all=true` for repeated patterns in gam_reporting_api.py All conversions follow SQLAlchemy 2.0 best practices.
Converted all `.query()` patterns in: - src/a2a_server/adcp_a2a_server.py (4 patterns) Changes: - Added `select` import from sqlalchemy - Converted `.query(DBPushNotificationConfig)` → `stmt = select(DBPushNotificationConfig)` - Converted `.filter_by()` → `.filter_by()` (chained with select) - Converted `.all()/.first()` → `db.scalars(stmt).all()/.first()` All push notification config queries now use SQLAlchemy 2.0 patterns.
Updated test_virtual_host_edge_cases.py to mock scalars() instead of query() to align with SQLAlchemy 2.0 patterns used in config_loader.py.
Updated remaining test assertions in test_virtual_host_edge_cases.py: - Removed outdated mock.query assertion in SQL injection test - Updated corrupted tenant test to mock scalars() chain - Tests now align with SQLAlchemy 2.0 patterns (select + scalars)
…0 (13 patterns) Converted all remaining .query() patterns in google_ad_manager_original.py: - Pattern 1 (line 405): Product lookup with filter_by - Pattern 2 (line 1834): CreativeFormat with filter, order_by, and in_() - Pattern 3 (line 2454): WorkflowStep with filter_by - Pattern 4 (line 2774): Tenant lookup with filter_by - Pattern 5 (line 2779): Product lookup with filter_by - Pattern 6 (line 2792): AdapterConfig with filter_by - Pattern 7 (line 2903): Product update with filter_by - Pattern 8 (line 2973): GAMInventory count with where - Pattern 9 (line 2989): GAMInventory all with where and and_() - Pattern 10 (line 3002): GAMInventory all with where and and_() - Pattern 11 (line 3046): GAMInventory all with where, and_(), and limit - Pattern 12 (line 3065): GAMInventory all with where, and_(), and limit - Pattern 13 (line 3089): GAMInventory column select with where and order_by (fixed typo: OrderBy → order_by) All patterns now use SQLAlchemy 2.0 API: - select() instead of query() - where() instead of filter() - scalars().first()/all() for entity queries - execute().first() for column-only queries - scalar() for count queries Note: This file appears to be legacy/deprecated (not imported anywhere). Migrated for completeness. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Fixed IndentationError in 5 test files caused by misplaced SQLAlchemy imports: - tests/smoke/test_smoke_critical_paths.py (line 482) - tests/integration/test_create_media_buy_v24.py (line 314) - tests/integration/test_gam_tenant_setup.py (line 227) - tests/integration/test_product_deletion.py (line 407) - tests/integration/test_tenant_management_api_integration.py (line 49) Also fixed SyntaxError in tests/manual/test_gam_automation_real.py: - Changed Product.tenant_id= to Product.tenant_id== in where() clauses Root cause: Automated migration script added imports in wrong location and used assignment operator instead of comparison operator in where(). All files now compile successfully. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
danf-newton
pushed a commit
to Newton-Research-Inc/salesagent
that referenced
this pull request
Nov 24, 2025
* Stage 5: Migrate src/core/ files to SQLAlchemy 2.0 Migrated 4 core files with 15 query patterns: - config_loader.py: 4 patterns (tenant lookups, subdomain/vhost resolution) - auth_utils.py: 5 patterns (principal/tenant auth lookups) - strategy.py: 5 patterns (strategy CRUD, simulation state management) - audit_logger.py: 2 patterns (tenant name lookups for notifications) All patterns converted from session.query() to select() + scalars(). Includes delete() pattern in strategy.py for reset() function. Related to PR prebid#307 - SQLAlchemy 2.0 migration initiative. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Stage 5: Migrate src/core/database/ files to SQLAlchemy 2.0 Migrated database.py with 1 count pattern: - Converted session.query(Tenant).count() to select(func.count()).select_from(Tenant) - Used scalar() instead of execute() for count queries Total core files migrated: 5 files, 16 patterns converted. Related to PR prebid#307 - SQLAlchemy 2.0 migration initiative. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Stage 5: Migrate format_metrics and dynamic_pricing services to SQLAlchemy 2.0 Migrated 2 service files with 2 query patterns: - format_metrics_service.py: 1 pattern (upsert query for metrics) - dynamic_pricing_service.py: 1 pattern (query with chained filters) Converted query().filter() to select().where() with scalars().all()/first(). Related to PR prebid#307 - SQLAlchemy 2.0 migration initiative. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Stage 5: Migrate push_notification_service to SQLAlchemy 2.0 Migrated push_notification_service.py with 5 query patterns: - Converted all .query() calls to select() + scalars() - Patterns include: filter_by, filter with and_(), and in_() clauses - Fixed import order (ruff) All query patterns now use SQLAlchemy 2.0 style with explicit stmt variables. Related to PR prebid#307 - SQLAlchemy 2.0 migration initiative. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Stage 5: Fix remaining .query() patterns in config_loader and update docs in database_session * Stage 5: Migrate GAM service files to SQLAlchemy 2.0 (24 patterns) Converted all `.query()` patterns in: - src/services/gam_inventory_service.py (17 patterns) - src/services/gam_orders_service.py (7 patterns) Changes: - Added `select`, `delete`, `update` imports - Converted `.query(Model)` → `stmt = select(Model)` - Converted `.filter()` → `.where()` - Converted `.all()/.first()` → `session.scalars(stmt).all()/.first()` - Converted `.update()` → `update(Model).values()` - Converted `.delete()` → `delete(Model).where()` - Converted `.count()` → `session.scalar(select(func.count()))` - Maintained readable formatting with proper variable names All conversions follow SQLAlchemy 2.0 best practices. * Stage 5: Migrate adapter files to SQLAlchemy 2.0 (18 patterns) Converted all `.query()` patterns in: - src/adapters/google_ad_manager.py (1 pattern) - src/adapters/mock_ad_server.py (1 pattern) - src/adapters/xandr.py (1 pattern) - src/adapters/gam_reporting_api.py (8 patterns) - src/adapters/gam/managers/sync.py (6 patterns) - src/adapters/gam/managers/workflow.py (1 pattern) Changes: - Added `select` imports (and `func` where needed for count operations) - Converted `.query(Model)` → `stmt = select(Model)` - Converted `.filter_by()` → `.filter_by()` (still supported in select) - Converted `.where()` for more complex filters - Converted `.all()/.first()` → `session.scalars(stmt).all()/.first()` - Converted `.count()` → `session.scalar(select(func.count()).select_from(Model).where(...))` - Used `replace_all=true` for repeated patterns in gam_reporting_api.py All conversions follow SQLAlchemy 2.0 best practices. * Stage 5: Migrate a2a_server file to SQLAlchemy 2.0 (4 patterns) Converted all `.query()` patterns in: - src/a2a_server/adcp_a2a_server.py (4 patterns) Changes: - Added `select` import from sqlalchemy - Converted `.query(DBPushNotificationConfig)` → `stmt = select(DBPushNotificationConfig)` - Converted `.filter_by()` → `.filter_by()` (chained with select) - Converted `.all()/.first()` → `db.scalars(stmt).all()/.first()` All push notification config queries now use SQLAlchemy 2.0 patterns. * Stage 5: Fix test to use scalars() mock for SQLAlchemy 2.0 Updated test_virtual_host_edge_cases.py to mock scalars() instead of query() to align with SQLAlchemy 2.0 patterns used in config_loader.py. * Stage 5: Complete test fixes for SQLAlchemy 2.0 Updated remaining test assertions in test_virtual_host_edge_cases.py: - Removed outdated mock.query assertion in SQL injection test - Updated corrupted tenant test to mock scalars() chain - Tests now align with SQLAlchemy 2.0 patterns (select + scalars) * Stage 5: Migrate google_ad_manager_original (legacy) to SQLAlchemy 2.0 (13 patterns) Converted all remaining .query() patterns in google_ad_manager_original.py: - Pattern 1 (line 405): Product lookup with filter_by - Pattern 2 (line 1834): CreativeFormat with filter, order_by, and in_() - Pattern 3 (line 2454): WorkflowStep with filter_by - Pattern 4 (line 2774): Tenant lookup with filter_by - Pattern 5 (line 2779): Product lookup with filter_by - Pattern 6 (line 2792): AdapterConfig with filter_by - Pattern 7 (line 2903): Product update with filter_by - Pattern 8 (line 2973): GAMInventory count with where - Pattern 9 (line 2989): GAMInventory all with where and and_() - Pattern 10 (line 3002): GAMInventory all with where and and_() - Pattern 11 (line 3046): GAMInventory all with where, and_(), and limit - Pattern 12 (line 3065): GAMInventory all with where, and_(), and limit - Pattern 13 (line 3089): GAMInventory column select with where and order_by (fixed typo: OrderBy → order_by) All patterns now use SQLAlchemy 2.0 API: - select() instead of query() - where() instead of filter() - scalars().first()/all() for entity queries - execute().first() for column-only queries - scalar() for count queries Note: This file appears to be legacy/deprecated (not imported anywhere). Migrated for completeness. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Stage 5: Fix syntax errors from automated test migration Fixed IndentationError in 5 test files caused by misplaced SQLAlchemy imports: - tests/smoke/test_smoke_critical_paths.py (line 482) - tests/integration/test_create_media_buy_v24.py (line 314) - tests/integration/test_gam_tenant_setup.py (line 227) - tests/integration/test_product_deletion.py (line 407) - tests/integration/test_tenant_management_api_integration.py (line 49) Also fixed SyntaxError in tests/manual/test_gam_automation_real.py: - Changed Product.tenant_id= to Product.tenant_id== in where() clauses Root cause: Automated migration script added imports in wrong location and used assignment operator instead of comparison operator in where(). All files now compile successfully. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR completes the SQLAlchemy 2.0 migration for the entire codebase by migrating all remaining source files and test files.
What Changed
Source Files Migrated (93 patterns total)
Test Files Migrated (148 patterns total)
Migration Patterns Applied
All code now uses SQLAlchemy 2.0 patterns:
Verification
✅ 479 unit tests passing (0 failures)
✅ 124+ integration tests passing
✅ 0 remaining
.query()patterns in src/ and tests/✅ All imports properly updated (select, delete, func from sqlalchemy)
✅ All pre-commit hooks passing
Testing Notes
.querysyntax - this is intentional and correct (mocking the old API)Related PRs
Documentation Updated
🎉 This completes the SQLAlchemy 2.0 migration for the entire codebase!