SIGN IN SIGN UP

Add `skipDuplicates` parameter on @entity directive (#6458)

* graph: parse skipDuplicates from @entity directive

Add kw::SKIP_DUPLICATES constant, skip_duplicates bool field to ObjectType,
and parsing logic in ObjectType::new() defaulting to false when absent.

* graph: validate skipDuplicates directive argument

Added SkipDuplicatesRequiresImmutable error variant, bool_arg validation
for skipDuplicates in validate_entity_directives(), and three test functions
covering non-boolean value, mutable entity, and timeseries+skipDuplicates.

* graph: expose skip_duplicates on EntityType and InputSchema APIs

Add TypeInfo::skip_duplicates(), InputSchema::skip_duplicates(), and
EntityType::skip_duplicates() following the is_immutable() three-layer
delegation pattern. Object types return immutable && skip_duplicates;
Interface and Aggregation types return false.

* graph, store: propagate skip_duplicates to RowGroup

Add skip_duplicates: bool field to RowGroup struct alongside immutable,
update RowGroup::new() to accept the parameter, and wire it from
entity_type.skip_duplicates() in RowGroups::group_entry(). All other
call sites (RowGroupForPerfTest, test helpers, example) pass false.

* graph, store: lenient write-batch enforcement for skip_duplicates

Modify RowGroup::append_row() so that when immutable=true and
skip_duplicates=true, cross-block duplicate inserts and
Overwrite/Remove operations log warnings and return Ok(()) instead
of failing. Same-block duplicates remain allowed. Default behavior
(skip_duplicates=false) is preserved exactly.

Added Logger field to RowGroup/RowGroups with CacheWeight impl,
threaded through all construction sites. 5 unit tests covering all
scenarios.

* store: propagate skip_duplicates to Table

Added skip_duplicates: bool field to Table struct in relational.rs,
wired from EntityType::skip_duplicates() in Table::new(), copied in
Table::new_like(), and defaulted to false in make_poi_table().

* store: lenient store-layer enforcement for skip_duplicates

Added logger parameter to Layout::update() and Layout::delete() in
relational.rs. When table.immutable && table.skip_duplicates, these
methods now log a warning and return Ok(0) instead of returning an
error. Default immutable behavior (skip_duplicates=false) is preserved.
Updated all callers including deployment_store.rs and test files.
Added 4 unit tests with SkipDupMink entity type to verify both
skip_duplicates and default immutable behavior.

* store: ON CONFLICT DO NOTHING for skip_duplicates inserts

Add conditional ON CONFLICT (primary_key) DO NOTHING clause to
InsertQuery::walk_ast() when table.immutable && table.skip_duplicates.
This handles cross-batch duplicates where an entity committed in a
previous batch is re-inserted due to the immutable entity cache
skipping store lookups.

Two unit tests verify: skip_duplicates inserts include ON CONFLICT,
default immutable inserts do not.

* store: log cross-batch duplicate inserts in Layout::insert()

Restructured Layout::insert() from if-let-Err to match to capture
affected_rows from InsertQuery::execute(). Tracks expected vs actual
row counts across both the main batch path and the row-by-row fallback
path. Logs a warning when affected_rows < expected for skip_duplicates
immutable tables.

* tests: runner test for skipDuplicates immutable entities

Add end-to-end runner test exercising @entity(immutable: true,
skipDuplicates: true) with duplicate entity inserts across blocks.

- tests/runner-tests/skip-duplicates/: subgraph with Ping entity using
  skipDuplicates, block handler that saves same ID every block
- tests/tests/runner_tests.rs: skip_duplicates() test syncs 4 blocks
  and verifies entity is queryable (indexing did not fail)

* graph, store: address review comments

- Remove logs and the logger from the RowGroup
- Simplify schema tests
- Add ObjectMutability enum instead of two booleans
I
Ion Suman committed
f031138757bd5f2a659aaad4a61895d0babe59b0
Parent: 4a00e8c
Committed by GitHub <noreply@github.com> on 4/9/2026, 3:20:19 PM