-
Notifications
You must be signed in to change notification settings - Fork 55
LCORE-741: quota limiter implementation for SQLite #702
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LCORE-741: quota limiter implementation for SQLite #702
Conversation
WalkthroughAdds SQLite support alongside PostgreSQL for quota management, introduces SQLite-specific SQL constants, and refactors cursor handling to use explicit cursor creation/closure with expanded exception handling in quota-related modules. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Limiter as RevokableQuotaLimiter
participant Config
participant SQLite_DB as SQLite
participant PG_DB as PostgreSQL
Client->>Limiter: available_quota()
Limiter->>Config: inspect sqlite_connection_config / postgres_connection_config
alt sqlite_connection_config present
Limiter->>SQLite_DB: open connection, create cursor (explicit)
SQLite_DB-->>Limiter: return rows
Limiter->>SQLite_DB: commit (when mutating)
Note right of Limiter: finally -> cursor.close() (guarded)
else postgres_connection_config present
Limiter->>PG_DB: with connection.cursor() as cur (context-managed)
PG_DB-->>Limiter: return rows
Note right of Limiter: context manager closes cursor
else
Limiter-->>Client: return 0
end
Limiter-->>Client: available quota value
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
🧰 Additional context used📓 Path-based instructions (2)src/**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.py📄 CodeRabbit inference engine (CLAUDE.md)
Files:
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
🔇 Additional comments (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/quota/revokable_quota_limiter.py (2)
103-108: Critical: Missing SQLite implementation.The
increase_quotamethod only implements the PostgreSQL path. This breaks SQLite support, which is the primary goal of this PR.Add the SQLite path:
# timestamp to be used updated_at = datetime.now() - with self.connection.cursor() as cursor: - cursor.execute( - UPDATE_AVAILABLE_QUOTA_PG, - (self.increase_by, updated_at, subject_id, self.subject_type), - ) - self.connection.commit() + if self.sqlite_connection_config is not None: + with self.connection.cursor() as cursor: + cursor.execute( + UPDATE_AVAILABLE_QUOTA_SQLITE, + (self.increase_by, updated_at, subject_id, self.subject_type), + ) + self.connection.commit() + if self.postgres_connection_config is not None: + with self.connection.cursor() as cursor: + cursor.execute( + UPDATE_AVAILABLE_QUOTA_PG, + (self.increase_by, updated_at, subject_id, self.subject_type), + ) + self.connection.commit()
175-201: Inconsistent cursor management patterns.The
_init_quotamethod also suffers from the same cursor management inconsistency.Apply the context manager pattern to the SQLite path:
if self.sqlite_connection_config is not None: - cursor = self.connection.cursor() - cursor.execute( - INIT_QUOTA_SQLITE, - ( - subject_id, - self.subject_type, - self.initial_quota, - self.initial_quota, - revoked_at, - ), - ) - cursor.close() - self.connection.commit() + with self.connection.cursor() as cursor: + cursor.execute( + INIT_QUOTA_SQLITE, + ( + subject_id, + self.subject_type, + self.initial_quota, + self.initial_quota, + revoked_at, + ), + ) + self.connection.commit()
🧹 Nitpick comments (2)
src/quota/quota_limiter.py (1)
78-92: Consider retaining the context manager pattern.The change from a context manager to manual cursor handling adds complexity without apparent benefit. Context managers automatically handle cleanup even on exceptions, making the code more robust and concise.
If you must use manual cursor management, the current implementation with the finally block is acceptable. However, consider reverting to the context manager pattern:
- cursor = None try: - cursor = self.connection.cursor() - cursor.execute("SELECT 1") + with self.connection.cursor() as cursor: + cursor.execute("SELECT 1") logger.info("Connection to storage is ok") return True except (psycopg2.OperationalError, sqlite3.Error) as e: logger.error("Disconnected from storage: %s", e) return False - finally: - if cursor is not None: - try: - cursor.close() - except Exception: # pylint: disable=broad-exception-caught - logger.warning("Unable to close cursor")src/quota/revokable_quota_limiter.py (1)
43-201: Consider extracting common database operation pattern.Each method duplicates the pattern of checking config type, creating cursor, executing SQL, and committing. This duplication increases maintenance burden.
Consider extracting a helper method:
def _execute_query( self, sqlite_sql: str, pg_sql: str, params: tuple, fetch: bool = False ) -> Any: """Execute query on the appropriate database backend.""" if self.sqlite_connection_config is not None: with self.connection.cursor() as cursor: cursor.execute(sqlite_sql, params) if fetch: return cursor.fetchone() self.connection.commit() elif self.postgres_connection_config is not None: with self.connection.cursor() as cursor: cursor.execute(pg_sql, params) if fetch: return cursor.fetchone() self.connection.commit() else: raise RuntimeError("No database configuration available")This would simplify all methods and ensure consistent patterns.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/quota/quota_limiter.py(1 hunks)src/quota/revokable_quota_limiter.py(6 hunks)src/quota/sql.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use absolute imports for internal modules (e.g., from auth import get_auth_dependency)
Files:
src/quota/sql.pysrc/quota/revokable_quota_limiter.pysrc/quota/quota_limiter.py
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: All modules start with descriptive module-level docstrings explaining purpose
Use logger = logging.getLogger(name) for module logging after import logging
Define type aliases at module level for clarity
All functions require docstrings with brief descriptions
Provide complete type annotations for all function parameters and return types
Use typing_extensions.Self in model validators where appropriate
Use modern union syntax (str | int) and Optional[T] or T | None consistently
Function names use snake_case with descriptive, action-oriented prefixes (get_, validate_, check_)
Avoid in-place parameter modification; return new data structures instead of mutating arguments
Use appropriate logging levels: debug, info, warning, error with clear messages
All classes require descriptive docstrings explaining purpose
Class names use PascalCase with conventional suffixes (Configuration, Error/Exception, Resolver, Interface)
Abstract base classes should use abc.ABC and @AbstractMethod for interfaces
Provide complete type annotations for all class attributes
Follow Google Python docstring style for modules, classes, and functions, including Args, Returns, Raises, Attributes sections as needed
Files:
src/quota/sql.pysrc/quota/revokable_quota_limiter.pysrc/quota/quota_limiter.py
🧬 Code graph analysis (2)
src/quota/revokable_quota_limiter.py (1)
src/utils/connection_decorator.py (1)
connection(6-22)
src/quota/quota_limiter.py (1)
src/utils/connection_decorator.py (1)
connection(6-22)
🪛 GitHub Actions: Pyright
src/quota/revokable_quota_limiter.py
[error] 43-43: Function with declared return type "int" must return value on all code paths. None is not assignable to "int" (reportReturnType)
src/quota/quota_limiter.py
[error] 84-84: "sqlite3" is not defined (reportUndefinedVariable)
🪛 GitHub Actions: Python linter
src/quota/revokable_quota_limiter.py
[error] 43-43: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
src/quota/quota_limiter.py
[error] 84-84: Undefined variable 'sqlite3' (undefined-variable). Likely missing an import for sqlite3.
🪛 GitHub Actions: Ruff
src/quota/quota_limiter.py
[error] 84-84: F821 Undefined name 'sqlite3' referenced in exception handling. Ensure sqlite3 is imported or referenced correctly.
🪛 GitHub Actions: Type checks
src/quota/revokable_quota_limiter.py
[error] 43-43: Mypy error: Missing return statement. [return]
src/quota/quota_limiter.py
[error] 84-84: Mypy error: Name 'sqlite3' is not defined. [name-defined]
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: build-pr
- GitHub Check: e2e_tests (azure)
- GitHub Check: e2e_tests (ci)
🔇 Additional comments (5)
src/quota/sql.py (4)
52-55: LGTM!The SQLite initialization query correctly mirrors the PostgreSQL variant with proper SQLite parameter placeholders.
60-67: LGTM!The SELECT query formatting is improved for consistency, and the SQLite variant correctly implements the same logic with appropriate parameter placeholders.
72-79: LGTM!Both PostgreSQL and SQLite UPDATE queries for setting available quota are syntactically correct with proper parameter placeholders.
84-91: LGTM!The UPDATE queries for incrementing available quota are correctly implemented for both database backends.
src/quota/revokable_quota_limiter.py (1)
13-19: LGTM!The SQLite SQL constants are correctly imported alongside their PostgreSQL counterparts.
src/quota/revokable_quota_limiter.py
Outdated
| if self.sqlite_connection_config is not None: | ||
| cursor = self.connection.cursor() | ||
| cursor.execute( | ||
| SELECT_QUOTA_PG, | ||
| SELECT_QUOTA_SQLITE, | ||
| (subject_id, self.subject_type), | ||
| ) | ||
| value = cursor.fetchone() | ||
| if value is None: | ||
| self._init_quota(subject_id) | ||
| return self.initial_quota | ||
| cursor.close() | ||
| return value[0] | ||
| if self.postgres_connection_config is not None: | ||
| with self.connection.cursor() as cursor: | ||
| cursor.execute( | ||
| SELECT_QUOTA_PG, | ||
| (subject_id, self.subject_type), | ||
| ) | ||
| value = cursor.fetchone() | ||
| if value is None: | ||
| self._init_quota(subject_id) | ||
| return self.initial_quota | ||
| return value[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent cursor management patterns.
The SQLite path uses manual cursor handling (create, close) while the PostgreSQL path uses a context manager. This inconsistency makes the code harder to maintain and more error-prone.
Consider unifying to context managers for both paths:
if self.sqlite_connection_config is not None:
- cursor = self.connection.cursor()
- cursor.execute(
- SELECT_QUOTA_SQLITE,
- (subject_id, self.subject_type),
- )
- value = cursor.fetchone()
- if value is None:
- self._init_quota(subject_id)
- return self.initial_quota
- cursor.close()
- return value[0]
+ with self.connection.cursor() as cursor:
+ cursor.execute(
+ SELECT_QUOTA_SQLITE,
+ (subject_id, self.subject_type),
+ )
+ value = cursor.fetchone()
+ if value is None:
+ self._init_quota(subject_id)
+ return self.initial_quota
+ return value[0]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if self.sqlite_connection_config is not None: | |
| cursor = self.connection.cursor() | |
| cursor.execute( | |
| SELECT_QUOTA_PG, | |
| SELECT_QUOTA_SQLITE, | |
| (subject_id, self.subject_type), | |
| ) | |
| value = cursor.fetchone() | |
| if value is None: | |
| self._init_quota(subject_id) | |
| return self.initial_quota | |
| cursor.close() | |
| return value[0] | |
| if self.postgres_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| cursor.execute( | |
| SELECT_QUOTA_PG, | |
| (subject_id, self.subject_type), | |
| ) | |
| value = cursor.fetchone() | |
| if value is None: | |
| self._init_quota(subject_id) | |
| return self.initial_quota | |
| return value[0] | |
| if self.sqlite_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| cursor.execute( | |
| SELECT_QUOTA_SQLITE, | |
| (subject_id, self.subject_type), | |
| ) | |
| value = cursor.fetchone() | |
| if value is None: | |
| self._init_quota(subject_id) | |
| return self.initial_quota | |
| return value[0] | |
| if self.postgres_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| cursor.execute( | |
| SELECT_QUOTA_PG, | |
| (subject_id, self.subject_type), | |
| ) | |
| value = cursor.fetchone() | |
| if value is None: | |
| self._init_quota(subject_id) | |
| return self.initial_quota | |
| return value[0] |
🤖 Prompt for AI Agents
In src/quota/revokable_quota_limiter.py around lines 47 to 69, the SQLite branch
manually creates and closes a cursor while the Postgres branch uses a context
manager; unify the patterns by using a context manager for the SQLite branch as
well (i.e., replace manual cursor creation/close with "with
self.connection.cursor() as cursor:"), and if the sqlite cursor implementation
in our environment does not support the context-manager protocol, replace the
manual approach with a try/finally that ensures cursor.close() in the finally
block so both branches guarantee deterministic cursor cleanup and match the
Postgres pattern.
Critical: Missing return statement for edge case.
The function must return a value on all code paths. If both sqlite_connection_config and postgres_connection_config are None, the function returns None implicitly, violating the return type annotation.
Add a fallback return or raise an exception:
if value is None:
self._init_quota(subject_id)
return self.initial_quota
return value[0]
+
+ raise RuntimeError("No database configuration available")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if self.sqlite_connection_config is not None: | |
| cursor = self.connection.cursor() | |
| cursor.execute( | |
| SELECT_QUOTA_PG, | |
| SELECT_QUOTA_SQLITE, | |
| (subject_id, self.subject_type), | |
| ) | |
| value = cursor.fetchone() | |
| if value is None: | |
| self._init_quota(subject_id) | |
| return self.initial_quota | |
| cursor.close() | |
| return value[0] | |
| if self.postgres_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| cursor.execute( | |
| SELECT_QUOTA_PG, | |
| (subject_id, self.subject_type), | |
| ) | |
| value = cursor.fetchone() | |
| if value is None: | |
| self._init_quota(subject_id) | |
| return self.initial_quota | |
| return value[0] | |
| if self.sqlite_connection_config is not None: | |
| cursor = self.connection.cursor() | |
| cursor.execute( | |
| SELECT_QUOTA_SQLITE, | |
| (subject_id, self.subject_type), | |
| ) | |
| value = cursor.fetchone() | |
| if value is None: | |
| self._init_quota(subject_id) | |
| return self.initial_quota | |
| cursor.close() | |
| return value[0] | |
| if self.postgres_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| cursor.execute( | |
| SELECT_QUOTA_PG, | |
| (subject_id, self.subject_type), | |
| ) | |
| value = cursor.fetchone() | |
| if value is None: | |
| self._init_quota(subject_id) | |
| return self.initial_quota | |
| return value[0] | |
| raise RuntimeError("No database configuration available") |
🤖 Prompt for AI Agents
In src/quota/revokable_quota_limiter.py around lines 47 to 69, the method can
fall through with both sqlite_connection_config and postgres_connection_config
being None and return None implicitly; add an explicit fallback to satisfy the
return type by raising a clear exception (e.g., RuntimeError or ValueError)
indicating no database backend is configured, or alternatively return a sensible
default (like self.initial_quota) depending on intended semantics; implement the
chosen fallback at the end of the function so every code path returns or raises.
src/quota/revokable_quota_limiter.py
Outdated
| if self.postgres_connection_config is not None: | ||
| with self.connection.cursor() as cursor: | ||
| cursor.execute( | ||
| SET_AVAILABLE_QUOTA_PG, | ||
| (self.initial_quota, revoked_at, subject_id, self.subject_type), | ||
| ) | ||
| self.connection.commit() | ||
| if self.sqlite_connection_config is not None: | ||
| cursor = self.connection.cursor() | ||
| cursor.execute( | ||
| SET_AVAILABLE_QUOTA_PG, | ||
| SET_AVAILABLE_QUOTA_SQLITE, | ||
| (self.initial_quota, revoked_at, subject_id, self.subject_type), | ||
| ) | ||
| self.connection.commit() | ||
| cursor.close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent cursor management patterns.
Same issue as in available_quota: SQLite uses manual cursor management while PostgreSQL uses a context manager.
Apply the same fix - use context managers for both paths:
if self.sqlite_connection_config is not None:
- cursor = self.connection.cursor()
- cursor.execute(
- SET_AVAILABLE_QUOTA_SQLITE,
- (self.initial_quota, revoked_at, subject_id, self.subject_type),
- )
- self.connection.commit()
- cursor.close()
+ with self.connection.cursor() as cursor:
+ cursor.execute(
+ SET_AVAILABLE_QUOTA_SQLITE,
+ (self.initial_quota, revoked_at, subject_id, self.subject_type),
+ )
+ self.connection.commit()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if self.postgres_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| cursor.execute( | |
| SET_AVAILABLE_QUOTA_PG, | |
| (self.initial_quota, revoked_at, subject_id, self.subject_type), | |
| ) | |
| self.connection.commit() | |
| if self.sqlite_connection_config is not None: | |
| cursor = self.connection.cursor() | |
| cursor.execute( | |
| SET_AVAILABLE_QUOTA_PG, | |
| SET_AVAILABLE_QUOTA_SQLITE, | |
| (self.initial_quota, revoked_at, subject_id, self.subject_type), | |
| ) | |
| self.connection.commit() | |
| cursor.close() | |
| if self.postgres_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| cursor.execute( | |
| SET_AVAILABLE_QUOTA_PG, | |
| (self.initial_quota, revoked_at, subject_id, self.subject_type), | |
| ) | |
| self.connection.commit() | |
| if self.sqlite_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| cursor.execute( | |
| SET_AVAILABLE_QUOTA_SQLITE, | |
| (self.initial_quota, revoked_at, subject_id, self.subject_type), | |
| ) | |
| self.connection.commit() |
🤖 Prompt for AI Agents
In src/quota/revokable_quota_limiter.py around lines 79 to 93, the SQLite branch
manually opens and closes a cursor while the PostgreSQL branch uses a context
manager; change the SQLite path to use a with self.connection.cursor() as cursor
context manager (like the Postgres branch), perform the execute inside that
context, call self.connection.commit() after the with block, and remove the
explicit cursor.close() to ensure consistent, safe cursor management.
src/quota/revokable_quota_limiter.py
Outdated
| if self.sqlite_connection_config is not None: | ||
| cursor = self.connection.cursor() | ||
| # timestamp to be used | ||
| updated_at = datetime.now() | ||
|
|
||
| cursor.execute( | ||
| UPDATE_AVAILABLE_QUOTA_PG, | ||
| UPDATE_AVAILABLE_QUOTA_SQLITE, | ||
| (-to_be_consumed, updated_at, subject_id, self.subject_type), | ||
| ) | ||
| self.connection.commit() | ||
| cursor.close() | ||
| if self.postgres_connection_config is not None: | ||
| with self.connection.cursor() as cursor: | ||
| # timestamp to be used | ||
| updated_at = datetime.now() | ||
|
|
||
| cursor.execute( | ||
| UPDATE_AVAILABLE_QUOTA_PG, | ||
| (-to_be_consumed, updated_at, subject_id, self.subject_type), | ||
| ) | ||
| self.connection.commit() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent cursor management patterns.
Same cursor management inconsistency: manual cursor handling for SQLite vs. context manager for PostgreSQL.
Unify to context managers:
if self.sqlite_connection_config is not None:
- cursor = self.connection.cursor()
- # timestamp to be used
- updated_at = datetime.now()
-
- cursor.execute(
- UPDATE_AVAILABLE_QUOTA_SQLITE,
- (-to_be_consumed, updated_at, subject_id, self.subject_type),
- )
- self.connection.commit()
- cursor.close()
+ with self.connection.cursor() as cursor:
+ # timestamp to be used
+ updated_at = datetime.now()
+
+ cursor.execute(
+ UPDATE_AVAILABLE_QUOTA_SQLITE,
+ (-to_be_consumed, updated_at, subject_id, self.subject_type),
+ )
+ self.connection.commit()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if self.sqlite_connection_config is not None: | |
| cursor = self.connection.cursor() | |
| # timestamp to be used | |
| updated_at = datetime.now() | |
| cursor.execute( | |
| UPDATE_AVAILABLE_QUOTA_PG, | |
| UPDATE_AVAILABLE_QUOTA_SQLITE, | |
| (-to_be_consumed, updated_at, subject_id, self.subject_type), | |
| ) | |
| self.connection.commit() | |
| cursor.close() | |
| if self.postgres_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| # timestamp to be used | |
| updated_at = datetime.now() | |
| cursor.execute( | |
| UPDATE_AVAILABLE_QUOTA_PG, | |
| (-to_be_consumed, updated_at, subject_id, self.subject_type), | |
| ) | |
| self.connection.commit() | |
| if self.sqlite_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| # timestamp to be used | |
| updated_at = datetime.now() | |
| cursor.execute( | |
| UPDATE_AVAILABLE_QUOTA_SQLITE, | |
| (-to_be_consumed, updated_at, subject_id, self.subject_type), | |
| ) | |
| self.connection.commit() | |
| if self.postgres_connection_config is not None: | |
| with self.connection.cursor() as cursor: | |
| # timestamp to be used | |
| updated_at = datetime.now() | |
| cursor.execute( | |
| UPDATE_AVAILABLE_QUOTA_PG, | |
| (-to_be_consumed, updated_at, subject_id, self.subject_type), | |
| ) | |
| self.connection.commit() |
🤖 Prompt for AI Agents
In src/quota/revokable_quota_limiter.py around lines 140 to 160, you currently
open and close the SQLite cursor manually but use a context manager for the
PostgreSQL cursor; unify both to context-manager style. Replace the manual
SQLite cursor block with a context-managed cursor (use
contextlib.closing(self.connection.cursor()) as cursor or use the connection as
a context manager and acquire the cursor inside) set updated_at inside the
block, execute UPDATE_AVAILABLE_QUOTA_SQLITE with the same parameters, call
self.connection.commit() after the with-block, and remove the explicit
cursor.close(); keep the PostgreSQL block as-is so both backends use
context-managed cursors and consistent timestamp/commit semantics.
d385cdc to
19ff7e8
Compare
19ff7e8 to
c8d5c85
Compare
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
Description
LCORE-741: quota limiter implementation for SQLite
Type of change
Related Tickets & Documents
Summary by CodeRabbit
New Features
Bug Fixes / Reliability