Chunk queries to avoid going over the sql parameter limit - #72

Merged
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters
Jun 12, 2026
Merged

Chunk queries to avoid going over the sql parameter limit#72
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters

Conversation

@hahn-kev

@hahn-kevhahn-kev commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

fixessillsdev/languageforge-lexbox#2339

Summary by CodeRabbit

  • Bug Fixes
    • Fixes filtering and sync behavior when very large batches exceed database parameter limits, preventing missed or duplicated records.
  • Chores
    • Improved performance and reliability when processing large numbers of snapshot updates.
  • Tests
    • Added tests that validate correct behavior under constrained database parameter limits.

@hahn-kev
hahn-kev requested a review from myieyeJune 11, 2026 03:55
@coderabbitai

coderabbitaiBot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Queries that used unbounded Contains/IN were changed to use EF.Parameter(...) for both snapshot and commit filtering; tests were added that lower SQLite’s variable limit to verify behavior when many IDs/entities are involved.

Changes

SQLite parameterization fixes

Layer / File(s)Summary
UpdateSnapshots: parameterized snapshot lookup
src/SIL.Harmony/DataModel.cs
Initializes snapshotLookup and, when commitsToApply.Count > 10, builds distinct entity IDs and queries repo.CurrentSnapshots() using EF.Parameter(entityIds).Contains(s.EntityId) to populate the lookup.
FilterExistingCommits: parameterized commit filter
src/SIL.Harmony/Db/CrdtRepository.cs
Precomputes commitIds and uses EF.Parameter(commitIds).Contains(c.Id) in the exclusion WHERE clause instead of inlining commits.Select(...).Contains(...).
SyncTests: SQLite-limit integration test
src/SIL.Harmony.Tests/SyncTests.cs
Adds using directives for Microsoft.Data.Sqlite/EF and a [Fact] that lowers SQLite's variable limit on the connection, creates commits whose total entity changes exceed that limit, runs AddRangeFromSync, and asserts final table counts.
RepositoryTests: FilterExistingCommits limit test
src/SIL.Harmony.Tests/RepositoryTests.cs
Adds Microsoft.Data.Sqlite using and a test that reduces SQLite's limit, inserts many commits, calls FilterExistingCommits, and asserts the count of filtered commits and oldest change identity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sillsdev/harmony#56: Modified UpdateSnapshots previously; this PR further adjusts snapshot-query behavior to avoid SQLite parameter overflow.

Suggested reviewers

  • myieye

Poem

🐰 I nibbled on binds and found a fix,
Batching IDs so queries play tricks,
SQLite's limits now softly yield,
Commits and snapshots safely sealed,
Hoppity happy — no more SQL mix!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and concisely describes the main change: implementing logic to avoid exceeding SQLite's parameter limit in queries.
Linked Issues check✅ PassedThe PR successfully addresses issue #2339 by implementing parameter limiting in both DataModel.UpdateSnapshots and CrdtRepository.FilterExistingCommits using EF.Parameter() to handle unbounded entity/commit ID lists.
Out of Scope Changes check✅ PassedAll changes are directly related to fixing the SQLite parameter limit issue: DataModel and CrdtRepository were modified to use EF.Parameter(), and comprehensive tests were added to validate the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prevent-too-many-parameters

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

myieye added 4 commits June 11, 2026 11:46
Appears to be significantly faster as the snapshot table grows. Only marginally slower on an empty DB.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/SIL.Harmony/Db/CrdtRepository.cs (1)

116-116: 💤 Low value

Consider materializing commitIds for clarity.

The deferred execution of commitIds is safe here because commits is an ICollection<Commit> (already materialized) and isn't modified before the query executes. However, materializing the projection explicitly would make the intent clearer and guard against subtle bugs if the code is refactored later.

♻️ Optional materialization for clarity
- var commitIds = commits.Select(c => c.Id);+ var commitIds = commits.Select(c => c.Id).ToArray();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/SIL.Harmony/Db/CrdtRepository.cs` at line 116, The projection assigned to
commitIds uses deferred LINQ (var commitIds = commits.Select(c => c.Id));
materialize it immediately to make intent explicit and guard against future
refactoring by replacing the assignment with an eagerly-evaluated collection
(e.g., commitIds = commits.Select(c => c.Id).ToList() or ToArray()); update the
code in CrdtRepository.cs where commitIds is defined so downstream usage
consumes the materialized list/array instead of an IEnumerable deferred query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/SIL.Harmony/Db/CrdtRepository.cs`:
- Line 116: The projection assigned to commitIds uses deferred LINQ (var
commitIds = commits.Select(c => c.Id)); materialize it immediately to make
intent explicit and guard against future refactoring by replacing the assignment
with an eagerly-evaluated collection (e.g., commitIds = commits.Select(c =>
c.Id).ToList() or ToArray()); update the code in CrdtRepository.cs where
commitIds is defined so downstream usage consumes the materialized list/array
instead of an IEnumerable deferred query.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9f376aa-aed7-446d-b899-404023c37a7d

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4e685 and dbe2d55.

📒 Files selected for processing (4)
  • src/SIL.Harmony.Tests/RepositoryTests.cs
  • src/SIL.Harmony.Tests/SyncTests.cs
  • src/SIL.Harmony/DataModel.cs
  • src/SIL.Harmony/Db/CrdtRepository.cs

@myieyemyieye left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude benchmarked your chunking fix vs just telling EF to emit a single parameter.

  • On an empty DB they're more or less equal (which is arguably the most common scenario that will run into this)
  • A single parameter (i.e. EF.Parameter) quickly becomes faster as the project gains content. E.g. with only 1,000 snapshots/commits it's already twice as fast and its advantage grows linearly with the size of the tables.

So, I refactored to EF.Parameter, which seemed to be the overall winner and is also a much smaller change.

Claude also noticed another spot that would have the same problem on big projects, so I fixed that too.

@hahn-kev

Copy link
Copy Markdown
CollaboratorAuthor

Awesome, I was wondering why it wasn't using json already, I didn't realize you could force it to do that using Parameter.

@hahn-kev
hahn-kev merged commit 7df9a3d into mainJun 12, 2026
6 checks passed
@hahn-kev
hahn-kev deleted the prevent-too-many-parameters branch June 12, 2026 01:57
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project download exception: 'too many SQL variables'

2 participants

@hahn-kev@myieye
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Chunk queries to avoid going over the sql parameter limit - #72

Merged
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters
Jun 12, 2026
Merged

Chunk queries to avoid going over the sql parameter limit#72
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters

Conversation

@hahn-kev

@hahn-kevhahn-kev commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

fixessillsdev/languageforge-lexbox#2339

Summary by CodeRabbit

  • Bug Fixes
    • Fixes filtering and sync behavior when very large batches exceed database parameter limits, preventing missed or duplicated records.
  • Chores
    • Improved performance and reliability when processing large numbers of snapshot updates.
  • Tests
    • Added tests that validate correct behavior under constrained database parameter limits.

@hahn-kev
hahn-kev requested a review from myieyeJune 11, 2026 03:55
@coderabbitai

coderabbitaiBot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Queries that used unbounded Contains/IN were changed to use EF.Parameter(...) for both snapshot and commit filtering; tests were added that lower SQLite’s variable limit to verify behavior when many IDs/entities are involved.

Changes

SQLite parameterization fixes

Layer / File(s)Summary
UpdateSnapshots: parameterized snapshot lookup
src/SIL.Harmony/DataModel.cs
Initializes snapshotLookup and, when commitsToApply.Count > 10, builds distinct entity IDs and queries repo.CurrentSnapshots() using EF.Parameter(entityIds).Contains(s.EntityId) to populate the lookup.
FilterExistingCommits: parameterized commit filter
src/SIL.Harmony/Db/CrdtRepository.cs
Precomputes commitIds and uses EF.Parameter(commitIds).Contains(c.Id) in the exclusion WHERE clause instead of inlining commits.Select(...).Contains(...).
SyncTests: SQLite-limit integration test
src/SIL.Harmony.Tests/SyncTests.cs
Adds using directives for Microsoft.Data.Sqlite/EF and a [Fact] that lowers SQLite's variable limit on the connection, creates commits whose total entity changes exceed that limit, runs AddRangeFromSync, and asserts final table counts.
RepositoryTests: FilterExistingCommits limit test
src/SIL.Harmony.Tests/RepositoryTests.cs
Adds Microsoft.Data.Sqlite using and a test that reduces SQLite's limit, inserts many commits, calls FilterExistingCommits, and asserts the count of filtered commits and oldest change identity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sillsdev/harmony#56: Modified UpdateSnapshots previously; this PR further adjusts snapshot-query behavior to avoid SQLite parameter overflow.

Suggested reviewers

  • myieye

Poem

🐰 I nibbled on binds and found a fix,
Batching IDs so queries play tricks,
SQLite's limits now softly yield,
Commits and snapshots safely sealed,
Hoppity happy — no more SQL mix!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and concisely describes the main change: implementing logic to avoid exceeding SQLite's parameter limit in queries.
Linked Issues check✅ PassedThe PR successfully addresses issue #2339 by implementing parameter limiting in both DataModel.UpdateSnapshots and CrdtRepository.FilterExistingCommits using EF.Parameter() to handle unbounded entity/commit ID lists.
Out of Scope Changes check✅ PassedAll changes are directly related to fixing the SQLite parameter limit issue: DataModel and CrdtRepository were modified to use EF.Parameter(), and comprehensive tests were added to validate the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prevent-too-many-parameters

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

myieye added 4 commits June 11, 2026 11:46
Appears to be significantly faster as the snapshot table grows. Only marginally slower on an empty DB.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/SIL.Harmony/Db/CrdtRepository.cs (1)

116-116: 💤 Low value

Consider materializing commitIds for clarity.

The deferred execution of commitIds is safe here because commits is an ICollection<Commit> (already materialized) and isn't modified before the query executes. However, materializing the projection explicitly would make the intent clearer and guard against subtle bugs if the code is refactored later.

♻️ Optional materialization for clarity
- var commitIds = commits.Select(c => c.Id);+ var commitIds = commits.Select(c => c.Id).ToArray();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/SIL.Harmony/Db/CrdtRepository.cs` at line 116, The projection assigned to
commitIds uses deferred LINQ (var commitIds = commits.Select(c => c.Id));
materialize it immediately to make intent explicit and guard against future
refactoring by replacing the assignment with an eagerly-evaluated collection
(e.g., commitIds = commits.Select(c => c.Id).ToList() or ToArray()); update the
code in CrdtRepository.cs where commitIds is defined so downstream usage
consumes the materialized list/array instead of an IEnumerable deferred query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/SIL.Harmony/Db/CrdtRepository.cs`:
- Line 116: The projection assigned to commitIds uses deferred LINQ (var
commitIds = commits.Select(c => c.Id)); materialize it immediately to make
intent explicit and guard against future refactoring by replacing the assignment
with an eagerly-evaluated collection (e.g., commitIds = commits.Select(c =>
c.Id).ToList() or ToArray()); update the code in CrdtRepository.cs where
commitIds is defined so downstream usage consumes the materialized list/array
instead of an IEnumerable deferred query.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9f376aa-aed7-446d-b899-404023c37a7d

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4e685 and dbe2d55.

📒 Files selected for processing (4)
  • src/SIL.Harmony.Tests/RepositoryTests.cs
  • src/SIL.Harmony.Tests/SyncTests.cs
  • src/SIL.Harmony/DataModel.cs
  • src/SIL.Harmony/Db/CrdtRepository.cs

@myieyemyieye left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude benchmarked your chunking fix vs just telling EF to emit a single parameter.

  • On an empty DB they're more or less equal (which is arguably the most common scenario that will run into this)
  • A single parameter (i.e. EF.Parameter) quickly becomes faster as the project gains content. E.g. with only 1,000 snapshots/commits it's already twice as fast and its advantage grows linearly with the size of the tables.

So, I refactored to EF.Parameter, which seemed to be the overall winner and is also a much smaller change.

Claude also noticed another spot that would have the same problem on big projects, so I fixed that too.

@hahn-kev

Copy link
Copy Markdown
CollaboratorAuthor

Awesome, I was wondering why it wasn't using json already, I didn't realize you could force it to do that using Parameter.

@hahn-kev
hahn-kev merged commit 7df9a3d into mainJun 12, 2026
6 checks passed
@hahn-kev
hahn-kev deleted the prevent-too-many-parameters branch June 12, 2026 01:57
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project download exception: 'too many SQL variables'

2 participants

@hahn-kev@myieye
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Chunk queries to avoid going over the sql parameter limit - #72

Merged
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters
Jun 12, 2026
Merged

Chunk queries to avoid going over the sql parameter limit#72
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters

Conversation

@hahn-kev

@hahn-kevhahn-kev commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

fixessillsdev/languageforge-lexbox#2339

Summary by CodeRabbit

  • Bug Fixes
    • Fixes filtering and sync behavior when very large batches exceed database parameter limits, preventing missed or duplicated records.
  • Chores
    • Improved performance and reliability when processing large numbers of snapshot updates.
  • Tests
    • Added tests that validate correct behavior under constrained database parameter limits.

@hahn-kev
hahn-kev requested a review from myieyeJune 11, 2026 03:55
@coderabbitai

coderabbitaiBot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Queries that used unbounded Contains/IN were changed to use EF.Parameter(...) for both snapshot and commit filtering; tests were added that lower SQLite’s variable limit to verify behavior when many IDs/entities are involved.

Changes

SQLite parameterization fixes

Layer / File(s)Summary
UpdateSnapshots: parameterized snapshot lookup
src/SIL.Harmony/DataModel.cs
Initializes snapshotLookup and, when commitsToApply.Count > 10, builds distinct entity IDs and queries repo.CurrentSnapshots() using EF.Parameter(entityIds).Contains(s.EntityId) to populate the lookup.
FilterExistingCommits: parameterized commit filter
src/SIL.Harmony/Db/CrdtRepository.cs
Precomputes commitIds and uses EF.Parameter(commitIds).Contains(c.Id) in the exclusion WHERE clause instead of inlining commits.Select(...).Contains(...).
SyncTests: SQLite-limit integration test
src/SIL.Harmony.Tests/SyncTests.cs
Adds using directives for Microsoft.Data.Sqlite/EF and a [Fact] that lowers SQLite's variable limit on the connection, creates commits whose total entity changes exceed that limit, runs AddRangeFromSync, and asserts final table counts.
RepositoryTests: FilterExistingCommits limit test
src/SIL.Harmony.Tests/RepositoryTests.cs
Adds Microsoft.Data.Sqlite using and a test that reduces SQLite's limit, inserts many commits, calls FilterExistingCommits, and asserts the count of filtered commits and oldest change identity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sillsdev/harmony#56: Modified UpdateSnapshots previously; this PR further adjusts snapshot-query behavior to avoid SQLite parameter overflow.

Suggested reviewers

  • myieye

Poem

🐰 I nibbled on binds and found a fix,
Batching IDs so queries play tricks,
SQLite's limits now softly yield,
Commits and snapshots safely sealed,
Hoppity happy — no more SQL mix!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and concisely describes the main change: implementing logic to avoid exceeding SQLite's parameter limit in queries.
Linked Issues check✅ PassedThe PR successfully addresses issue #2339 by implementing parameter limiting in both DataModel.UpdateSnapshots and CrdtRepository.FilterExistingCommits using EF.Parameter() to handle unbounded entity/commit ID lists.
Out of Scope Changes check✅ PassedAll changes are directly related to fixing the SQLite parameter limit issue: DataModel and CrdtRepository were modified to use EF.Parameter(), and comprehensive tests were added to validate the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prevent-too-many-parameters

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

myieye added 4 commits June 11, 2026 11:46
Appears to be significantly faster as the snapshot table grows. Only marginally slower on an empty DB.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/SIL.Harmony/Db/CrdtRepository.cs (1)

116-116: 💤 Low value

Consider materializing commitIds for clarity.

The deferred execution of commitIds is safe here because commits is an ICollection<Commit> (already materialized) and isn't modified before the query executes. However, materializing the projection explicitly would make the intent clearer and guard against subtle bugs if the code is refactored later.

♻️ Optional materialization for clarity
- var commitIds = commits.Select(c => c.Id);+ var commitIds = commits.Select(c => c.Id).ToArray();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/SIL.Harmony/Db/CrdtRepository.cs` at line 116, The projection assigned to
commitIds uses deferred LINQ (var commitIds = commits.Select(c => c.Id));
materialize it immediately to make intent explicit and guard against future
refactoring by replacing the assignment with an eagerly-evaluated collection
(e.g., commitIds = commits.Select(c => c.Id).ToList() or ToArray()); update the
code in CrdtRepository.cs where commitIds is defined so downstream usage
consumes the materialized list/array instead of an IEnumerable deferred query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/SIL.Harmony/Db/CrdtRepository.cs`:
- Line 116: The projection assigned to commitIds uses deferred LINQ (var
commitIds = commits.Select(c => c.Id)); materialize it immediately to make
intent explicit and guard against future refactoring by replacing the assignment
with an eagerly-evaluated collection (e.g., commitIds = commits.Select(c =>
c.Id).ToList() or ToArray()); update the code in CrdtRepository.cs where
commitIds is defined so downstream usage consumes the materialized list/array
instead of an IEnumerable deferred query.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9f376aa-aed7-446d-b899-404023c37a7d

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4e685 and dbe2d55.

📒 Files selected for processing (4)
  • src/SIL.Harmony.Tests/RepositoryTests.cs
  • src/SIL.Harmony.Tests/SyncTests.cs
  • src/SIL.Harmony/DataModel.cs
  • src/SIL.Harmony/Db/CrdtRepository.cs

@myieyemyieye left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude benchmarked your chunking fix vs just telling EF to emit a single parameter.

  • On an empty DB they're more or less equal (which is arguably the most common scenario that will run into this)
  • A single parameter (i.e. EF.Parameter) quickly becomes faster as the project gains content. E.g. with only 1,000 snapshots/commits it's already twice as fast and its advantage grows linearly with the size of the tables.

So, I refactored to EF.Parameter, which seemed to be the overall winner and is also a much smaller change.

Claude also noticed another spot that would have the same problem on big projects, so I fixed that too.

@hahn-kev

Copy link
Copy Markdown
CollaboratorAuthor

Awesome, I was wondering why it wasn't using json already, I didn't realize you could force it to do that using Parameter.

@hahn-kev
hahn-kev merged commit 7df9a3d into mainJun 12, 2026
6 checks passed
@hahn-kev
hahn-kev deleted the prevent-too-many-parameters branch June 12, 2026 01:57
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project download exception: 'too many SQL variables'

2 participants

@hahn-kev@myieye
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Chunk queries to avoid going over the sql parameter limit - #72

Merged
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters
Jun 12, 2026
Merged

Chunk queries to avoid going over the sql parameter limit#72
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters

Conversation

@hahn-kev

@hahn-kevhahn-kev commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

fixessillsdev/languageforge-lexbox#2339

Summary by CodeRabbit

  • Bug Fixes
    • Fixes filtering and sync behavior when very large batches exceed database parameter limits, preventing missed or duplicated records.
  • Chores
    • Improved performance and reliability when processing large numbers of snapshot updates.
  • Tests
    • Added tests that validate correct behavior under constrained database parameter limits.

@hahn-kev
hahn-kev requested a review from myieyeJune 11, 2026 03:55
@coderabbitai

coderabbitaiBot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Queries that used unbounded Contains/IN were changed to use EF.Parameter(...) for both snapshot and commit filtering; tests were added that lower SQLite’s variable limit to verify behavior when many IDs/entities are involved.

Changes

SQLite parameterization fixes

Layer / File(s)Summary
UpdateSnapshots: parameterized snapshot lookup
src/SIL.Harmony/DataModel.cs
Initializes snapshotLookup and, when commitsToApply.Count > 10, builds distinct entity IDs and queries repo.CurrentSnapshots() using EF.Parameter(entityIds).Contains(s.EntityId) to populate the lookup.
FilterExistingCommits: parameterized commit filter
src/SIL.Harmony/Db/CrdtRepository.cs
Precomputes commitIds and uses EF.Parameter(commitIds).Contains(c.Id) in the exclusion WHERE clause instead of inlining commits.Select(...).Contains(...).
SyncTests: SQLite-limit integration test
src/SIL.Harmony.Tests/SyncTests.cs
Adds using directives for Microsoft.Data.Sqlite/EF and a [Fact] that lowers SQLite's variable limit on the connection, creates commits whose total entity changes exceed that limit, runs AddRangeFromSync, and asserts final table counts.
RepositoryTests: FilterExistingCommits limit test
src/SIL.Harmony.Tests/RepositoryTests.cs
Adds Microsoft.Data.Sqlite using and a test that reduces SQLite's limit, inserts many commits, calls FilterExistingCommits, and asserts the count of filtered commits and oldest change identity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sillsdev/harmony#56: Modified UpdateSnapshots previously; this PR further adjusts snapshot-query behavior to avoid SQLite parameter overflow.

Suggested reviewers

  • myieye

Poem

🐰 I nibbled on binds and found a fix,
Batching IDs so queries play tricks,
SQLite's limits now softly yield,
Commits and snapshots safely sealed,
Hoppity happy — no more SQL mix!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and concisely describes the main change: implementing logic to avoid exceeding SQLite's parameter limit in queries.
Linked Issues check✅ PassedThe PR successfully addresses issue #2339 by implementing parameter limiting in both DataModel.UpdateSnapshots and CrdtRepository.FilterExistingCommits using EF.Parameter() to handle unbounded entity/commit ID lists.
Out of Scope Changes check✅ PassedAll changes are directly related to fixing the SQLite parameter limit issue: DataModel and CrdtRepository were modified to use EF.Parameter(), and comprehensive tests were added to validate the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prevent-too-many-parameters

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

myieye added 4 commits June 11, 2026 11:46
Appears to be significantly faster as the snapshot table grows. Only marginally slower on an empty DB.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/SIL.Harmony/Db/CrdtRepository.cs (1)

116-116: 💤 Low value

Consider materializing commitIds for clarity.

The deferred execution of commitIds is safe here because commits is an ICollection<Commit> (already materialized) and isn't modified before the query executes. However, materializing the projection explicitly would make the intent clearer and guard against subtle bugs if the code is refactored later.

♻️ Optional materialization for clarity
- var commitIds = commits.Select(c => c.Id);+ var commitIds = commits.Select(c => c.Id).ToArray();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/SIL.Harmony/Db/CrdtRepository.cs` at line 116, The projection assigned to
commitIds uses deferred LINQ (var commitIds = commits.Select(c => c.Id));
materialize it immediately to make intent explicit and guard against future
refactoring by replacing the assignment with an eagerly-evaluated collection
(e.g., commitIds = commits.Select(c => c.Id).ToList() or ToArray()); update the
code in CrdtRepository.cs where commitIds is defined so downstream usage
consumes the materialized list/array instead of an IEnumerable deferred query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/SIL.Harmony/Db/CrdtRepository.cs`:
- Line 116: The projection assigned to commitIds uses deferred LINQ (var
commitIds = commits.Select(c => c.Id)); materialize it immediately to make
intent explicit and guard against future refactoring by replacing the assignment
with an eagerly-evaluated collection (e.g., commitIds = commits.Select(c =>
c.Id).ToList() or ToArray()); update the code in CrdtRepository.cs where
commitIds is defined so downstream usage consumes the materialized list/array
instead of an IEnumerable deferred query.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9f376aa-aed7-446d-b899-404023c37a7d

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4e685 and dbe2d55.

📒 Files selected for processing (4)
  • src/SIL.Harmony.Tests/RepositoryTests.cs
  • src/SIL.Harmony.Tests/SyncTests.cs
  • src/SIL.Harmony/DataModel.cs
  • src/SIL.Harmony/Db/CrdtRepository.cs

@myieyemyieye left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude benchmarked your chunking fix vs just telling EF to emit a single parameter.

  • On an empty DB they're more or less equal (which is arguably the most common scenario that will run into this)
  • A single parameter (i.e. EF.Parameter) quickly becomes faster as the project gains content. E.g. with only 1,000 snapshots/commits it's already twice as fast and its advantage grows linearly with the size of the tables.

So, I refactored to EF.Parameter, which seemed to be the overall winner and is also a much smaller change.

Claude also noticed another spot that would have the same problem on big projects, so I fixed that too.

@hahn-kev

Copy link
Copy Markdown
CollaboratorAuthor

Awesome, I was wondering why it wasn't using json already, I didn't realize you could force it to do that using Parameter.

@hahn-kev
hahn-kev merged commit 7df9a3d into mainJun 12, 2026
6 checks passed
@hahn-kev
hahn-kev deleted the prevent-too-many-parameters branch June 12, 2026 01:57
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project download exception: 'too many SQL variables'

2 participants

@hahn-kev@myieye
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Chunk queries to avoid going over the sql parameter limit - #72

Merged
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters
Jun 12, 2026
Merged

Chunk queries to avoid going over the sql parameter limit#72
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters

Conversation

@hahn-kev

@hahn-kevhahn-kev commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

fixessillsdev/languageforge-lexbox#2339

Summary by CodeRabbit

  • Bug Fixes
    • Fixes filtering and sync behavior when very large batches exceed database parameter limits, preventing missed or duplicated records.
  • Chores
    • Improved performance and reliability when processing large numbers of snapshot updates.
  • Tests
    • Added tests that validate correct behavior under constrained database parameter limits.

@hahn-kev
hahn-kev requested a review from myieyeJune 11, 2026 03:55
@coderabbitai

coderabbitaiBot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Queries that used unbounded Contains/IN were changed to use EF.Parameter(...) for both snapshot and commit filtering; tests were added that lower SQLite’s variable limit to verify behavior when many IDs/entities are involved.

Changes

SQLite parameterization fixes

Layer / File(s)Summary
UpdateSnapshots: parameterized snapshot lookup
src/SIL.Harmony/DataModel.cs
Initializes snapshotLookup and, when commitsToApply.Count > 10, builds distinct entity IDs and queries repo.CurrentSnapshots() using EF.Parameter(entityIds).Contains(s.EntityId) to populate the lookup.
FilterExistingCommits: parameterized commit filter
src/SIL.Harmony/Db/CrdtRepository.cs
Precomputes commitIds and uses EF.Parameter(commitIds).Contains(c.Id) in the exclusion WHERE clause instead of inlining commits.Select(...).Contains(...).
SyncTests: SQLite-limit integration test
src/SIL.Harmony.Tests/SyncTests.cs
Adds using directives for Microsoft.Data.Sqlite/EF and a [Fact] that lowers SQLite's variable limit on the connection, creates commits whose total entity changes exceed that limit, runs AddRangeFromSync, and asserts final table counts.
RepositoryTests: FilterExistingCommits limit test
src/SIL.Harmony.Tests/RepositoryTests.cs
Adds Microsoft.Data.Sqlite using and a test that reduces SQLite's limit, inserts many commits, calls FilterExistingCommits, and asserts the count of filtered commits and oldest change identity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sillsdev/harmony#56: Modified UpdateSnapshots previously; this PR further adjusts snapshot-query behavior to avoid SQLite parameter overflow.

Suggested reviewers

  • myieye

Poem

🐰 I nibbled on binds and found a fix,
Batching IDs so queries play tricks,
SQLite's limits now softly yield,
Commits and snapshots safely sealed,
Hoppity happy — no more SQL mix!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and concisely describes the main change: implementing logic to avoid exceeding SQLite's parameter limit in queries.
Linked Issues check✅ PassedThe PR successfully addresses issue #2339 by implementing parameter limiting in both DataModel.UpdateSnapshots and CrdtRepository.FilterExistingCommits using EF.Parameter() to handle unbounded entity/commit ID lists.
Out of Scope Changes check✅ PassedAll changes are directly related to fixing the SQLite parameter limit issue: DataModel and CrdtRepository were modified to use EF.Parameter(), and comprehensive tests were added to validate the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prevent-too-many-parameters

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

myieye added 4 commits June 11, 2026 11:46
Appears to be significantly faster as the snapshot table grows. Only marginally slower on an empty DB.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/SIL.Harmony/Db/CrdtRepository.cs (1)

116-116: 💤 Low value

Consider materializing commitIds for clarity.

The deferred execution of commitIds is safe here because commits is an ICollection<Commit> (already materialized) and isn't modified before the query executes. However, materializing the projection explicitly would make the intent clearer and guard against subtle bugs if the code is refactored later.

♻️ Optional materialization for clarity
- var commitIds = commits.Select(c => c.Id);+ var commitIds = commits.Select(c => c.Id).ToArray();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/SIL.Harmony/Db/CrdtRepository.cs` at line 116, The projection assigned to
commitIds uses deferred LINQ (var commitIds = commits.Select(c => c.Id));
materialize it immediately to make intent explicit and guard against future
refactoring by replacing the assignment with an eagerly-evaluated collection
(e.g., commitIds = commits.Select(c => c.Id).ToList() or ToArray()); update the
code in CrdtRepository.cs where commitIds is defined so downstream usage
consumes the materialized list/array instead of an IEnumerable deferred query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/SIL.Harmony/Db/CrdtRepository.cs`:
- Line 116: The projection assigned to commitIds uses deferred LINQ (var
commitIds = commits.Select(c => c.Id)); materialize it immediately to make
intent explicit and guard against future refactoring by replacing the assignment
with an eagerly-evaluated collection (e.g., commitIds = commits.Select(c =>
c.Id).ToList() or ToArray()); update the code in CrdtRepository.cs where
commitIds is defined so downstream usage consumes the materialized list/array
instead of an IEnumerable deferred query.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9f376aa-aed7-446d-b899-404023c37a7d

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4e685 and dbe2d55.

📒 Files selected for processing (4)
  • src/SIL.Harmony.Tests/RepositoryTests.cs
  • src/SIL.Harmony.Tests/SyncTests.cs
  • src/SIL.Harmony/DataModel.cs
  • src/SIL.Harmony/Db/CrdtRepository.cs

@myieyemyieye left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude benchmarked your chunking fix vs just telling EF to emit a single parameter.

  • On an empty DB they're more or less equal (which is arguably the most common scenario that will run into this)
  • A single parameter (i.e. EF.Parameter) quickly becomes faster as the project gains content. E.g. with only 1,000 snapshots/commits it's already twice as fast and its advantage grows linearly with the size of the tables.

So, I refactored to EF.Parameter, which seemed to be the overall winner and is also a much smaller change.

Claude also noticed another spot that would have the same problem on big projects, so I fixed that too.

@hahn-kev

Copy link
Copy Markdown
CollaboratorAuthor

Awesome, I was wondering why it wasn't using json already, I didn't realize you could force it to do that using Parameter.

@hahn-kev
hahn-kev merged commit 7df9a3d into mainJun 12, 2026
6 checks passed
@hahn-kev
hahn-kev deleted the prevent-too-many-parameters branch June 12, 2026 01:57
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project download exception: 'too many SQL variables'

2 participants

@hahn-kev@myieye
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Chunk queries to avoid going over the sql parameter limit - #72

Merged
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters
Jun 12, 2026
Merged

Chunk queries to avoid going over the sql parameter limit#72
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters

Conversation

@hahn-kev

@hahn-kevhahn-kev commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

fixessillsdev/languageforge-lexbox#2339

Summary by CodeRabbit

  • Bug Fixes
    • Fixes filtering and sync behavior when very large batches exceed database parameter limits, preventing missed or duplicated records.
  • Chores
    • Improved performance and reliability when processing large numbers of snapshot updates.
  • Tests
    • Added tests that validate correct behavior under constrained database parameter limits.

@hahn-kev
hahn-kev requested a review from myieyeJune 11, 2026 03:55
@coderabbitai

coderabbitaiBot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Queries that used unbounded Contains/IN were changed to use EF.Parameter(...) for both snapshot and commit filtering; tests were added that lower SQLite’s variable limit to verify behavior when many IDs/entities are involved.

Changes

SQLite parameterization fixes

Layer / File(s)Summary
UpdateSnapshots: parameterized snapshot lookup
src/SIL.Harmony/DataModel.cs
Initializes snapshotLookup and, when commitsToApply.Count > 10, builds distinct entity IDs and queries repo.CurrentSnapshots() using EF.Parameter(entityIds).Contains(s.EntityId) to populate the lookup.
FilterExistingCommits: parameterized commit filter
src/SIL.Harmony/Db/CrdtRepository.cs
Precomputes commitIds and uses EF.Parameter(commitIds).Contains(c.Id) in the exclusion WHERE clause instead of inlining commits.Select(...).Contains(...).
SyncTests: SQLite-limit integration test
src/SIL.Harmony.Tests/SyncTests.cs
Adds using directives for Microsoft.Data.Sqlite/EF and a [Fact] that lowers SQLite's variable limit on the connection, creates commits whose total entity changes exceed that limit, runs AddRangeFromSync, and asserts final table counts.
RepositoryTests: FilterExistingCommits limit test
src/SIL.Harmony.Tests/RepositoryTests.cs
Adds Microsoft.Data.Sqlite using and a test that reduces SQLite's limit, inserts many commits, calls FilterExistingCommits, and asserts the count of filtered commits and oldest change identity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sillsdev/harmony#56: Modified UpdateSnapshots previously; this PR further adjusts snapshot-query behavior to avoid SQLite parameter overflow.

Suggested reviewers

  • myieye

Poem

🐰 I nibbled on binds and found a fix,
Batching IDs so queries play tricks,
SQLite's limits now softly yield,
Commits and snapshots safely sealed,
Hoppity happy — no more SQL mix!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and concisely describes the main change: implementing logic to avoid exceeding SQLite's parameter limit in queries.
Linked Issues check✅ PassedThe PR successfully addresses issue #2339 by implementing parameter limiting in both DataModel.UpdateSnapshots and CrdtRepository.FilterExistingCommits using EF.Parameter() to handle unbounded entity/commit ID lists.
Out of Scope Changes check✅ PassedAll changes are directly related to fixing the SQLite parameter limit issue: DataModel and CrdtRepository were modified to use EF.Parameter(), and comprehensive tests were added to validate the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prevent-too-many-parameters

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

myieye added 4 commits June 11, 2026 11:46
Appears to be significantly faster as the snapshot table grows. Only marginally slower on an empty DB.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/SIL.Harmony/Db/CrdtRepository.cs (1)

116-116: 💤 Low value

Consider materializing commitIds for clarity.

The deferred execution of commitIds is safe here because commits is an ICollection<Commit> (already materialized) and isn't modified before the query executes. However, materializing the projection explicitly would make the intent clearer and guard against subtle bugs if the code is refactored later.

♻️ Optional materialization for clarity
- var commitIds = commits.Select(c => c.Id);+ var commitIds = commits.Select(c => c.Id).ToArray();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/SIL.Harmony/Db/CrdtRepository.cs` at line 116, The projection assigned to
commitIds uses deferred LINQ (var commitIds = commits.Select(c => c.Id));
materialize it immediately to make intent explicit and guard against future
refactoring by replacing the assignment with an eagerly-evaluated collection
(e.g., commitIds = commits.Select(c => c.Id).ToList() or ToArray()); update the
code in CrdtRepository.cs where commitIds is defined so downstream usage
consumes the materialized list/array instead of an IEnumerable deferred query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/SIL.Harmony/Db/CrdtRepository.cs`:
- Line 116: The projection assigned to commitIds uses deferred LINQ (var
commitIds = commits.Select(c => c.Id)); materialize it immediately to make
intent explicit and guard against future refactoring by replacing the assignment
with an eagerly-evaluated collection (e.g., commitIds = commits.Select(c =>
c.Id).ToList() or ToArray()); update the code in CrdtRepository.cs where
commitIds is defined so downstream usage consumes the materialized list/array
instead of an IEnumerable deferred query.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9f376aa-aed7-446d-b899-404023c37a7d

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4e685 and dbe2d55.

📒 Files selected for processing (4)
  • src/SIL.Harmony.Tests/RepositoryTests.cs
  • src/SIL.Harmony.Tests/SyncTests.cs
  • src/SIL.Harmony/DataModel.cs
  • src/SIL.Harmony/Db/CrdtRepository.cs

@myieyemyieye left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude benchmarked your chunking fix vs just telling EF to emit a single parameter.

  • On an empty DB they're more or less equal (which is arguably the most common scenario that will run into this)
  • A single parameter (i.e. EF.Parameter) quickly becomes faster as the project gains content. E.g. with only 1,000 snapshots/commits it's already twice as fast and its advantage grows linearly with the size of the tables.

So, I refactored to EF.Parameter, which seemed to be the overall winner and is also a much smaller change.

Claude also noticed another spot that would have the same problem on big projects, so I fixed that too.

@hahn-kev

Copy link
Copy Markdown
CollaboratorAuthor

Awesome, I was wondering why it wasn't using json already, I didn't realize you could force it to do that using Parameter.

@hahn-kev
hahn-kev merged commit 7df9a3d into mainJun 12, 2026
6 checks passed
@hahn-kev
hahn-kev deleted the prevent-too-many-parameters branch June 12, 2026 01:57
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project download exception: 'too many SQL variables'

2 participants

@hahn-kev@myieye
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Chunk queries to avoid going over the sql parameter limit - #72

Merged
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters
Jun 12, 2026
Merged

Chunk queries to avoid going over the sql parameter limit#72
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters

Conversation

@hahn-kev

@hahn-kevhahn-kev commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

fixessillsdev/languageforge-lexbox#2339

Summary by CodeRabbit

  • Bug Fixes
    • Fixes filtering and sync behavior when very large batches exceed database parameter limits, preventing missed or duplicated records.
  • Chores
    • Improved performance and reliability when processing large numbers of snapshot updates.
  • Tests
    • Added tests that validate correct behavior under constrained database parameter limits.

@hahn-kev
hahn-kev requested a review from myieyeJune 11, 2026 03:55
@coderabbitai

coderabbitaiBot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Queries that used unbounded Contains/IN were changed to use EF.Parameter(...) for both snapshot and commit filtering; tests were added that lower SQLite’s variable limit to verify behavior when many IDs/entities are involved.

Changes

SQLite parameterization fixes

Layer / File(s)Summary
UpdateSnapshots: parameterized snapshot lookup
src/SIL.Harmony/DataModel.cs
Initializes snapshotLookup and, when commitsToApply.Count > 10, builds distinct entity IDs and queries repo.CurrentSnapshots() using EF.Parameter(entityIds).Contains(s.EntityId) to populate the lookup.
FilterExistingCommits: parameterized commit filter
src/SIL.Harmony/Db/CrdtRepository.cs
Precomputes commitIds and uses EF.Parameter(commitIds).Contains(c.Id) in the exclusion WHERE clause instead of inlining commits.Select(...).Contains(...).
SyncTests: SQLite-limit integration test
src/SIL.Harmony.Tests/SyncTests.cs
Adds using directives for Microsoft.Data.Sqlite/EF and a [Fact] that lowers SQLite's variable limit on the connection, creates commits whose total entity changes exceed that limit, runs AddRangeFromSync, and asserts final table counts.
RepositoryTests: FilterExistingCommits limit test
src/SIL.Harmony.Tests/RepositoryTests.cs
Adds Microsoft.Data.Sqlite using and a test that reduces SQLite's limit, inserts many commits, calls FilterExistingCommits, and asserts the count of filtered commits and oldest change identity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sillsdev/harmony#56: Modified UpdateSnapshots previously; this PR further adjusts snapshot-query behavior to avoid SQLite parameter overflow.

Suggested reviewers

  • myieye

Poem

🐰 I nibbled on binds and found a fix,
Batching IDs so queries play tricks,
SQLite's limits now softly yield,
Commits and snapshots safely sealed,
Hoppity happy — no more SQL mix!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and concisely describes the main change: implementing logic to avoid exceeding SQLite's parameter limit in queries.
Linked Issues check✅ PassedThe PR successfully addresses issue #2339 by implementing parameter limiting in both DataModel.UpdateSnapshots and CrdtRepository.FilterExistingCommits using EF.Parameter() to handle unbounded entity/commit ID lists.
Out of Scope Changes check✅ PassedAll changes are directly related to fixing the SQLite parameter limit issue: DataModel and CrdtRepository were modified to use EF.Parameter(), and comprehensive tests were added to validate the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prevent-too-many-parameters

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

myieye added 4 commits June 11, 2026 11:46
Appears to be significantly faster as the snapshot table grows. Only marginally slower on an empty DB.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/SIL.Harmony/Db/CrdtRepository.cs (1)

116-116: 💤 Low value

Consider materializing commitIds for clarity.

The deferred execution of commitIds is safe here because commits is an ICollection<Commit> (already materialized) and isn't modified before the query executes. However, materializing the projection explicitly would make the intent clearer and guard against subtle bugs if the code is refactored later.

♻️ Optional materialization for clarity
- var commitIds = commits.Select(c => c.Id);+ var commitIds = commits.Select(c => c.Id).ToArray();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/SIL.Harmony/Db/CrdtRepository.cs` at line 116, The projection assigned to
commitIds uses deferred LINQ (var commitIds = commits.Select(c => c.Id));
materialize it immediately to make intent explicit and guard against future
refactoring by replacing the assignment with an eagerly-evaluated collection
(e.g., commitIds = commits.Select(c => c.Id).ToList() or ToArray()); update the
code in CrdtRepository.cs where commitIds is defined so downstream usage
consumes the materialized list/array instead of an IEnumerable deferred query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/SIL.Harmony/Db/CrdtRepository.cs`:
- Line 116: The projection assigned to commitIds uses deferred LINQ (var
commitIds = commits.Select(c => c.Id)); materialize it immediately to make
intent explicit and guard against future refactoring by replacing the assignment
with an eagerly-evaluated collection (e.g., commitIds = commits.Select(c =>
c.Id).ToList() or ToArray()); update the code in CrdtRepository.cs where
commitIds is defined so downstream usage consumes the materialized list/array
instead of an IEnumerable deferred query.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9f376aa-aed7-446d-b899-404023c37a7d

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4e685 and dbe2d55.

📒 Files selected for processing (4)
  • src/SIL.Harmony.Tests/RepositoryTests.cs
  • src/SIL.Harmony.Tests/SyncTests.cs
  • src/SIL.Harmony/DataModel.cs
  • src/SIL.Harmony/Db/CrdtRepository.cs

@myieyemyieye left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude benchmarked your chunking fix vs just telling EF to emit a single parameter.

  • On an empty DB they're more or less equal (which is arguably the most common scenario that will run into this)
  • A single parameter (i.e. EF.Parameter) quickly becomes faster as the project gains content. E.g. with only 1,000 snapshots/commits it's already twice as fast and its advantage grows linearly with the size of the tables.

So, I refactored to EF.Parameter, which seemed to be the overall winner and is also a much smaller change.

Claude also noticed another spot that would have the same problem on big projects, so I fixed that too.

@hahn-kev

Copy link
Copy Markdown
CollaboratorAuthor

Awesome, I was wondering why it wasn't using json already, I didn't realize you could force it to do that using Parameter.

@hahn-kev
hahn-kev merged commit 7df9a3d into mainJun 12, 2026
6 checks passed
@hahn-kev
hahn-kev deleted the prevent-too-many-parameters branch June 12, 2026 01:57
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project download exception: 'too many SQL variables'

2 participants

@hahn-kev@myieye
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Chunk queries to avoid going over the sql parameter limit - #72

Merged
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters
Jun 12, 2026
Merged

Chunk queries to avoid going over the sql parameter limit#72
hahn-kev merged 5 commits into
mainfrom
prevent-too-many-parameters

Conversation

@hahn-kev

@hahn-kevhahn-kev commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

fixessillsdev/languageforge-lexbox#2339

Summary by CodeRabbit

  • Bug Fixes
    • Fixes filtering and sync behavior when very large batches exceed database parameter limits, preventing missed or duplicated records.
  • Chores
    • Improved performance and reliability when processing large numbers of snapshot updates.
  • Tests
    • Added tests that validate correct behavior under constrained database parameter limits.

@hahn-kev
hahn-kev requested a review from myieyeJune 11, 2026 03:55
@coderabbitai

coderabbitaiBot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Queries that used unbounded Contains/IN were changed to use EF.Parameter(...) for both snapshot and commit filtering; tests were added that lower SQLite’s variable limit to verify behavior when many IDs/entities are involved.

Changes

SQLite parameterization fixes

Layer / File(s)Summary
UpdateSnapshots: parameterized snapshot lookup
src/SIL.Harmony/DataModel.cs
Initializes snapshotLookup and, when commitsToApply.Count > 10, builds distinct entity IDs and queries repo.CurrentSnapshots() using EF.Parameter(entityIds).Contains(s.EntityId) to populate the lookup.
FilterExistingCommits: parameterized commit filter
src/SIL.Harmony/Db/CrdtRepository.cs
Precomputes commitIds and uses EF.Parameter(commitIds).Contains(c.Id) in the exclusion WHERE clause instead of inlining commits.Select(...).Contains(...).
SyncTests: SQLite-limit integration test
src/SIL.Harmony.Tests/SyncTests.cs
Adds using directives for Microsoft.Data.Sqlite/EF and a [Fact] that lowers SQLite's variable limit on the connection, creates commits whose total entity changes exceed that limit, runs AddRangeFromSync, and asserts final table counts.
RepositoryTests: FilterExistingCommits limit test
src/SIL.Harmony.Tests/RepositoryTests.cs
Adds Microsoft.Data.Sqlite using and a test that reduces SQLite's limit, inserts many commits, calls FilterExistingCommits, and asserts the count of filtered commits and oldest change identity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sillsdev/harmony#56: Modified UpdateSnapshots previously; this PR further adjusts snapshot-query behavior to avoid SQLite parameter overflow.

Suggested reviewers

  • myieye

Poem

🐰 I nibbled on binds and found a fix,
Batching IDs so queries play tricks,
SQLite's limits now softly yield,
Commits and snapshots safely sealed,
Hoppity happy — no more SQL mix!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately and concisely describes the main change: implementing logic to avoid exceeding SQLite's parameter limit in queries.
Linked Issues check✅ PassedThe PR successfully addresses issue #2339 by implementing parameter limiting in both DataModel.UpdateSnapshots and CrdtRepository.FilterExistingCommits using EF.Parameter() to handle unbounded entity/commit ID lists.
Out of Scope Changes check✅ PassedAll changes are directly related to fixing the SQLite parameter limit issue: DataModel and CrdtRepository were modified to use EF.Parameter(), and comprehensive tests were added to validate the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prevent-too-many-parameters

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

myieye added 4 commits June 11, 2026 11:46
Appears to be significantly faster as the snapshot table grows. Only marginally slower on an empty DB.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/SIL.Harmony/Db/CrdtRepository.cs (1)

116-116: 💤 Low value

Consider materializing commitIds for clarity.

The deferred execution of commitIds is safe here because commits is an ICollection<Commit> (already materialized) and isn't modified before the query executes. However, materializing the projection explicitly would make the intent clearer and guard against subtle bugs if the code is refactored later.

♻️ Optional materialization for clarity
- var commitIds = commits.Select(c => c.Id);+ var commitIds = commits.Select(c => c.Id).ToArray();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/SIL.Harmony/Db/CrdtRepository.cs` at line 116, The projection assigned to
commitIds uses deferred LINQ (var commitIds = commits.Select(c => c.Id));
materialize it immediately to make intent explicit and guard against future
refactoring by replacing the assignment with an eagerly-evaluated collection
(e.g., commitIds = commits.Select(c => c.Id).ToList() or ToArray()); update the
code in CrdtRepository.cs where commitIds is defined so downstream usage
consumes the materialized list/array instead of an IEnumerable deferred query.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/SIL.Harmony/Db/CrdtRepository.cs`:
- Line 116: The projection assigned to commitIds uses deferred LINQ (var
commitIds = commits.Select(c => c.Id)); materialize it immediately to make
intent explicit and guard against future refactoring by replacing the assignment
with an eagerly-evaluated collection (e.g., commitIds = commits.Select(c =>
c.Id).ToList() or ToArray()); update the code in CrdtRepository.cs where
commitIds is defined so downstream usage consumes the materialized list/array
instead of an IEnumerable deferred query.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9f376aa-aed7-446d-b899-404023c37a7d

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4e685 and dbe2d55.

📒 Files selected for processing (4)
  • src/SIL.Harmony.Tests/RepositoryTests.cs
  • src/SIL.Harmony.Tests/SyncTests.cs
  • src/SIL.Harmony/DataModel.cs
  • src/SIL.Harmony/Db/CrdtRepository.cs

@myieyemyieye left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude benchmarked your chunking fix vs just telling EF to emit a single parameter.

  • On an empty DB they're more or less equal (which is arguably the most common scenario that will run into this)
  • A single parameter (i.e. EF.Parameter) quickly becomes faster as the project gains content. E.g. with only 1,000 snapshots/commits it's already twice as fast and its advantage grows linearly with the size of the tables.

So, I refactored to EF.Parameter, which seemed to be the overall winner and is also a much smaller change.

Claude also noticed another spot that would have the same problem on big projects, so I fixed that too.

@hahn-kev

Copy link
Copy Markdown
CollaboratorAuthor

Awesome, I was wondering why it wasn't using json already, I didn't realize you could force it to do that using Parameter.

@hahn-kev
hahn-kev merged commit 7df9a3d into mainJun 12, 2026
6 checks passed
@hahn-kev
hahn-kev deleted the prevent-too-many-parameters branch June 12, 2026 01:57
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project download exception: 'too many SQL variables'

2 participants

@hahn-kev@myieye