Skip to content

refactor: migrate db.session.query to select in infra layer#33694

Merged
asukaminato0721 merged 2 commits intolanggenius:mainfrom
RenzoMXD:refactor/select-api-migration-infra
Mar 19, 2026
Merged

refactor: migrate db.session.query to select in infra layer#33694
asukaminato0721 merged 2 commits intolanggenius:mainfrom
RenzoMXD:refactor/select-api-migration-infra

Conversation

@RenzoMXD
Copy link
Copy Markdown
Contributor

Summary

  • Migrate legacy db.session.query() calls to SQLAlchemy 2.0 select() API
    across infrastructure modules: schedule/, events/, commands/,
    extensions/, and factories/
  • Replace .filter_by().delete() and .filter_by().update() with
    execute(delete(...)) and execute(update(...))
  • Add .limit(1) to non-primary-key lookups to preserve the implicit
    LIMIT 1 behavior of the legacy .first() method
  • 14 files modified, no test changes required

Test plan

  • ruff check passes on all modified files
  • Unit tests pass (factories/, tasks/)
  • No db.session.query or session.query remaining in modified files

Closes #22668 (partial)

@RenzoMXD RenzoMXD requested a review from QuantumGhost as a code owner March 18, 2026 15:20
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. refactor labels Mar 18, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors database interaction code across several core modules to align with SQLAlchemy 2.0's modern API. The changes involve updating query construction, delete operations, and update statements to use the newer select, delete, and update constructs, enhancing consistency and preparing the codebase for future SQLAlchemy advancements. This modernization effort improves maintainability and leverages the latest features of the ORM.

Highlights

  • SQLAlchemy 2.0 Migration: Migrated legacy db.session.query() calls to the SQLAlchemy 2.0 select() API across schedule/, events/, commands/, extensions/, and factories/ modules.
  • Modernized DML Operations: Replaced .filter_by().delete() and .filter_by().update() patterns with execute(delete(...)) and execute(update(...)) for improved SQLAlchemy 2.0 compatibility.
  • Implicit LIMIT 1 Preservation: Added .limit(1) to non-primary-key lookups when migrating from the legacy .first() method to ensure the implicit LIMIT 1 behavior is maintained.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@RenzoMXD RenzoMXD changed the title refactor(api): Query API to select function_2 refactor: migrate db.session.query to select in infra layer Mar 18, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-03-18 15:24:32.189801172 +0000
+++ /tmp/pyrefly_pr.txt	2026-03-18 15:24:22.229825478 +0000
@@ -1,3 +1,11 @@
+ERROR Object of class `Result` has no attribute `rowcount` [missing-attribute]
+  --> commands/plugin.py:52:21
+ERROR Object of class `Result` has no attribute `rowcount` [missing-attribute]
+   --> commands/plugin.py:99:21
+ERROR Object of class `Result` has no attribute `rowcount` [missing-attribute]
+   --> commands/plugin.py:139:21
+ERROR Object of class `Result` has no attribute `rowcount` [missing-attribute]
+   --> commands/storage.py:744:27
 ERROR `result` may be uninitialized [unbound-name]
    --> controllers/console/app/annotation.py:126:16
 ERROR Object of class `App` has no attribute `access_mode` [missing-attribute]

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request successfully migrates various SQLAlchemy 1.x query syntaxes to the SQLAlchemy 2.0 style across multiple files. This includes updating db.session.query().filter_by().delete() to db.session.execute(delete().where()), db.session.query().filter_by().all() to db.session.scalars(select().where()).all(), and db.session.query().filter_by().first() to db.session.scalar(select().where()). These changes are consistent with the SQLAlchemy 2.0 migration guide and improve code readability and maintainability by using explicit select, delete, and update statements. No critical or high-severity issues were found.

@RenzoMXD RenzoMXD force-pushed the refactor/select-api-migration-infra branch from a21517c to fff9482 Compare March 18, 2026 16:32
@github-actions
Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-03-18 16:33:16.538087374 +0000
+++ /tmp/pyrefly_pr.txt	2026-03-18 16:33:07.576042124 +0000
@@ -1,3 +1,11 @@
+ERROR Object of class `Result` has no attribute `rowcount` [missing-attribute]
+  --> commands/plugin.py:52:21
+ERROR Object of class `Result` has no attribute `rowcount` [missing-attribute]
+   --> commands/plugin.py:99:21
+ERROR Object of class `Result` has no attribute `rowcount` [missing-attribute]
+   --> commands/plugin.py:139:21
+ERROR Object of class `Result` has no attribute `rowcount` [missing-attribute]
+   --> commands/storage.py:744:27
 ERROR `result` may be uninitialized [unbound-name]
    --> controllers/console/app/annotation.py:126:16
 ERROR Object of class `App` has no attribute `access_mode` [missing-attribute]

@RenzoMXD RenzoMXD force-pushed the refactor/select-api-migration-infra branch from fff9482 to 5d9655d Compare March 18, 2026 16:34
@github-actions
Copy link
Copy Markdown
Contributor

Pyrefly Diff

No changes detected.

@github-actions
Copy link
Copy Markdown
Contributor

Pyrefly Diff

No changes detected.

@asukaminato0721
Copy link
Copy Markdown
Contributor

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request successfully migrates various database query and update operations from the legacy SQLAlchemy 1.x API to the modern SQLAlchemy 2.0 style. This refactoring improves code clarity, leverages newer features, and aligns with current best practices for SQLAlchemy usage. The changes are consistently applied across multiple files, including api/commands/plugin.py, api/commands/storage.py, api/commands/system.py, api/commands/vector.py, api/events/event_handlers/create_document_index.py, api/events/event_handlers/update_app_dataset_join_when_app_model_config_updated.py, api/events/event_handlers/update_app_dataset_join_when_app_published_workflow_updated.py, api/extensions/ext_login.py, api/factories/file_factory.py, api/schedule/check_upgradable_plugin_task.py, api/schedule/clean_embedding_cache_task.py, api/schedule/clean_unused_datasets_task.py, api/schedule/create_tidb_serverless_task.py, and api/schedule/mail_clean_document_notify_task.py. The use of session.scalars() for fetching multiple entities, session.scalar() for single entities, and session.execute() for DML operations (DELETE, UPDATE) is correctly implemented. Additionally, the explicit inclusion of .limit(1) in queries expecting a single result enhances readability and intent.

@RenzoMXD
Copy link
Copy Markdown
Contributor Author

@asukaminato0721 Please review again.

@asukaminato0721
Copy link
Copy Markdown
Contributor

Could you split this into smaller pr?
Each pr has ~50 LoC diff
The non-cast part seems good, I am not sure cast part works.

@RenzoMXD
Copy link
Copy Markdown
Contributor Author

Could you split this into smaller pr? Each pr has ~50 LoC diff The non-cast part seems good, I am not sure cast part works.

@dosu

How to implement none-cast code for "--- /tmp/pyrefly_base.txt 2026-03-18 16:33:16.538087374 +0000
+++ /tmp/pyrefly_pr.txt 2026-03-18 16:33:07.576042124 +0000
@@ -1,3 +1,11 @@
+ERROR Object of class Result has no attribute rowcount [missing-attribute]

  • --> commands/plugin.py:52:21
    +ERROR Object of class Result has no attribute rowcount [missing-attribute]
  • --> commands/plugin.py:99:21
    +ERROR Object of class Result has no attribute rowcount [missing-attribute]
  • --> commands/plugin.py:139:21
    +ERROR Object of class Result has no attribute rowcount [missing-attribute]
  • --> commands/storage.py:744:27
    ERROR result may be uninitialized [unbound-name]
    --> controllers/console/app/annotation.py:126:16
    ERROR Object of class App has no attribute access_mode [missing-attribute]"

Please give me your opinion.

@dosubot
Copy link
Copy Markdown

dosubot bot commented Mar 19, 2026

The pyrefly type errors are occurring because when you migrate from the legacy .query().delete() pattern to execute(delete(...)), SQLAlchemy 2.0's execute() returns a generic Result object, but only CursorResult (a subtype) has the rowcount attribute.

The fix: use cast(CursorResult, ...)

from sqlalchemy.engine import CursorResult
from typing import cast

# Instead of:
result = session.execute(delete(Model).where(...))
rows_deleted = result.rowcount  # Type error!

# Do this:
result = cast(CursorResult, session.execute(delete(Model).where(...)))
rows_deleted = result.rowcount  # ✓ No error

This pattern is already used throughout Dify's codebase. See examples in:

The cast() is needed because DML operations (DELETE, UPDATE, INSERT) return CursorResult which has rowcount, but the type checker only sees the generic Result return type.

This is the standard type-safe pattern in Dify—the maintainer's concern about the cast part is unfounded since it's consistent with existing code.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor  Share on X

@RenzoMXD
Copy link
Copy Markdown
Contributor Author

RenzoMXD commented Mar 19, 2026

@asukaminato0721 Thanks for your review.
I am sorry but I prepared more than 20 PRs for future code changes. So please review this PR and I'll make small PRs with ~50 lines after this. And then without cast, CI tests are failed and cast are already used in this repository.
Please take an another look on it.

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Mar 19, 2026
@asukaminato0721 asukaminato0721 merged commit 8a22cc0 into langgenius:main Mar 19, 2026
13 of 14 checks passed
@RenzoMXD RenzoMXD deleted the refactor/select-api-migration-infra branch March 19, 2026 11:36
@RenzoMXD
Copy link
Copy Markdown
Contributor Author

@asukaminato0721 Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer refactor size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

use select style api in orm

2 participants