Skip to content

feat: add UpsertAsync/UpsertBulkAsync - #142

Merged
mrdevrobot merged 2 commits into
mainfrom
feat/upsert-139
Sep 3, 2026
Merged

feat: add UpsertAsync/UpsertBulkAsync#142
mrdevrobot merged 2 commits into
mainfrom
feat/upsert-139

Conversation

@mrdevrobot

Copy link
Copy Markdown
Contributor

Summary

Closes #139. Adds UpsertAsync/UpsertBulkAsync to both DocumentCollection<TId,T> and DynamicCollection, returning UpsertResult<TId> (Id, Inserted).

Not a Find followed by a separate InsertAsync/UpdateAsync call — each document is resolved with a single primary-index lookup inside one transaction: found → replace at that location, not found → insert. That avoids the double lookup, extra lock/transaction cycle, and check-then-act race a naive wrapper would carry. When the entity's id is unset, the lookup is skipped entirely since no existing document could match it.

  • DocumentCollection<TId,T>: UpsertAsync, UpsertBulkAsync on both the interface and implementation.
  • DynamicCollection: same shape over BsonDocument, keyed by BsonId.
  • Refactored UpdateDataCore/UpdateAsync (both classes) to split out the post-lookup write path (UpdateAtLocationCore) so Upsert's update branch reuses it without a second lookup.
  • CDC and metrics report the operation as Insert or Update based on what actually happened — no synthetic "Upsert" event type was introduced.
  • README updated with typed-API and schema-less-API examples.

Test plan

  • dotnet build on BLite.Core, BLite, BLite.SourceGenerators (Debug + Release) — clean
  • New tests: tests/BLite.Tests/UpsertTests.cs (typed DocumentCollection<TId,T>), tests/BLite.Tests/UpsertDynamicCollectionTests.cs (DynamicCollection) — insert path, replace path, no-duplicate-key behavior, bulk mix of inserts/updates
  • Full dotnet test tests/BLite.Tests — 2337 passed; only 3 pre-existing, unrelated MultiProcessWalSharedMemoryTests failures (cross-process WAL lock timeouts, untouched by this diff)

🤖 Generated with Claude Code

Insert-or-replace resolved with a single primary-index lookup per
document inside one transaction, not a Find followed by a separate
Insert/Update call — avoids the double lookup, extra lock/transaction
cycle, and check-then-act race a naive wrapper would have.

- DocumentCollection<TId,T>: UpsertAsync/UpsertBulkAsync, returning
  UpsertResult<TId> (Id, Inserted). Skips the lookup entirely when the
  entity's id is unset, since no existing document could match it.
- DynamicCollection: same UpsertAsync/UpsertBulkAsync over BsonDocument,
  returning UpsertResult<BsonId>.
- Refactors UpdateDataCore/UpdateAsync to split out the post-lookup
  write path (UpdateAtLocationCore) so Upsert's update branch reuses it
  without a second primary-index lookup.
- CDC and metrics report the operation as Insert or Update based on
  what actually happened; no synthetic "Upsert" event type was added.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 3, 2026 20:44
@mrdevrobot mrdevrobot self-assigned this Sep 3, 2026
@mrdevrobot mrdevrobot added enhancement New feature or request documentation Improvements or additions to documentation core labels Sep 3, 2026
@mrdevrobot mrdevrobot added this to BLite Sep 3, 2026
@github-project-automation github-project-automation Bot moved this to Todo in BLite Sep 3, 2026

Copilot AI 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.

🟡 Changes recommended

The typed upsert update path ignores UpdateAtLocationCore’s failure return and can report a successful replace when no update actually occurred.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds first-class upsert support to BLite’s typed (DocumentCollection<TId,T>) and schema-less (DynamicCollection) APIs, returning a new UpsertResult<TId> that reports the resolved id and whether the call inserted vs replaced. The implementation aims to resolve each document with a single primary-index lookup inside a transaction, and includes new tests and README examples.

Changes:

  • Added UpsertAsync / UpsertBulkAsync to IDocumentCollection<TId,T> + DocumentCollection<TId,T> and to DynamicCollection.
  • Refactored update internals to allow “update-at-known-location” so upsert update paths don’t re-lookup keys.
  • Added new tests for typed and dynamic upsert paths; updated README with usage examples.
File summaries
File Description
tests/BLite.Tests/UpsertTests.cs New typed upsert test coverage (insert/replace/bulk behaviors).
tests/BLite.Tests/UpsertDynamicCollectionTests.cs New schema-less upsert test coverage (insert/replace/bulk behaviors).
src/BLite.Core/DynamicCollection.cs Adds UpsertAsync/UpsertBulkAsync and refactors update path to reuse a resolved location.
src/BLite.Core/Collections/UpsertResult.cs Introduces UpsertResult<TId> return type for upsert operations.
src/BLite.Core/Collections/IDocumentCollection.cs Extends the public typed collection interface with upsert APIs.
src/BLite.Core/Collections/DocumentCollection.cs Implements typed upsert APIs and refactors update to support update-at-location reuse.
README.md Documents upsert usage for typed and schema-less APIs.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/BLite.Core/Collections/DocumentCollection.cs
…appen

UpsertCore's update branch ignored UpdateAtLocationCore's return value.
UpdateAtLocationCore returns false when the primary index resolves a
location but the stored document can't be read (stale/corrupted index
entry) — UpsertAsync/UpsertBulkAsync would then report a successful
replace (Inserted: false) even though nothing was actually written.

Now throws instead of lying about the outcome.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
mrdevrobot added a commit to EntglDb/BLite.Website that referenced this pull request Sep 3, 2026
…I pages

Adds the Upsert section previously stubbed as "not yet available" in CRUD.vue,
and a matching section + API reference rows in DynamicAPI.vue, for the new
UpsertAsync/UpsertBulkAsync API landing in BLite (EntglDb/BLite#142).

Also adds deploy/publish-prod.sh + deploy/.env.example to publish this site
to Plesk (blitedb.com), mirroring the pattern used in the WebSites repo but
adapted for this project's Vite SSG build (npm run build -> dist/).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
mrdevrobot added a commit to EntglDb/BLite.Website that referenced this pull request Sep 3, 2026
Updates package.json, Hero badge, App.vue/Studio.vue footer download
links (Studio v5.1.0 assets), and the Installation.vue NuGet version
snippet ahead of the BLite 5.1.0 release (adds UpsertAsync/UpsertBulkAsync,
EntglDb/BLite#142).

Left BLite.Server-specific version references (server-docs/VersionMatrix.vue,
server-docs/Overview.vue) untouched — BLite.Server's compatibility with
engine 5.1.0 hasn't been verified, that repo hasn't been touched here.
Also left historical "BLite X.Y.Z adds/introduces ..." feature-origin
callouts (Encryption/AuditTrail/GDPR docs, router SEO descriptions) as-is
since they describe when a feature shipped, not the current version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@mrdevrobot
mrdevrobot merged commit dd31ff2 into main Sep 3, 2026
6 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to QA in BLite Sep 3, 2026
@mrdevrobot
mrdevrobot deleted the feat/upsert-139 branch September 3, 2026 20:58
@mrdevrobot mrdevrobot mentioned this pull request Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core documentation Improvements or additions to documentation enhancement New feature or request

Projects

Status: QA

Development

Successfully merging this pull request may close these issues.

add Upsert functions

2 participants