Skip to content

fix(unique): include language in value identity - #9820

Open
gooohgb wants to merge 3 commits into
dgraph-io:mainfrom
gooohgb:fix-unique-lang-identity
Open

fix(unique): include language in value identity#9820
gooohgb wants to merge 3 commits into
dgraph-io:mainfrom
gooohgb:fix-unique-lang-identity

Conversation

@gooohgb

@gooohgb gooohgb commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes #9815.

For predicates using both @unique and @lang, equal values under different
language tags were handled inconsistently.

The database-level uniqueness query generated by addQueryIfUnique already
scopes values by language, such as gxid@en and gxid@fr. However,
verifyUniqueWithinMutation compared only the predicate and value, causing
equal values under different languages in the same mutation to be incorrectly
rejected as duplicates.

This change includes the language tag when checking value identity within a
mutation. It also applies the same rule to isSwap, preventing a mutation of
one language from being mistaken for releasing a unique value stored under
another language.

Predicates without language tags retain their existing behavior because both
language values are empty.

Regression coverage includes:

  • Equal values under the same language are rejected.
  • Equal values under different languages are accepted.
  • Equal untagged values are rejected.
  • Tagged and untagged values are treated independently.
  • Swap detection only considers mutations under the same language.
  • The reported DQL mutation is covered in TestUniqueForLangDirective.

Checklist

  • The PR title follows the
    Conventional Commits syntax, leading
    with fix:, feat:, chore:, ci:, etc.
  • Code compiles correctly and linting (via trunk) passes locally
  • Tests added for new functionality, or regression tests for bug fixes added as applicable

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@gooohgb
gooohgb requested a review from a team as a code owner September 1, 2026 02:24
Comment thread edgraph/server_test.go
require.Equal(t, hex.EncodeToString(h.Sum(nil)), getHash(10, 20))
}

func TestVerifyUniqueWithinMutationLanguageIdentity(t *testing.T) {

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.

@gooohgb Thanks for the fix.
One ask: three of the important cases are only covered by unit tests right now. Unit tests check the new comparison logic in isolation, but they don't prove the whole flow (mutation → uniqueness query → verify) behaves correctly against a real cluster. Could you add integration tests for these three?

1. Tagged + untagged value in separate mutations (both orders)
First commit _:a <name> "x" (no language), then in a new mutation try _:b <name@en> "x" —and also the other way around. Your unit test says these two are different values and both should be accepted. But whether the database-side check agrees depends on how eq(name, "x") behaves when the value is stored under a language tag and that's never actually tested. If the DB side sees them as the same value, we end up with the same "works in separate mutations, fails in one mutation" inconsistency this PR is fixing just for the tagged/untagged pair instead of en/fr.

2. Swap across two languages (must now FAIL)
Node X already has "v"@en. One mutation gives "v"@en to a new node and at the same time changes X's @fr value. Before this PR that slipped a real duplicate past @unique; with your fix it must be rejected. That's the most valuable behavior change in the PR, and it currently has no end-to-end test.

3. Swap within the same language (must still SUCCEED)
Node X changes its "v"@en to "w"@en while a new node takes "v"@en the classic legal swap, just on a @lang predicate. The existing swap tests only use a predicate without @lang.

Two small side notes:

  • Now that language is part of the value's identity, the duplicate error could say which one: predicate [gxid@en] instead of predicate [gxid]. Cheap to add and makes the error self-explanatory.
  • The PR says "Fixes fix(unique): @unique and @lang disagree on whether language is part of value identity #9815", which will auto-close the issue but the issue's minor second point (the __dgraph_uniquecheck_N__ variable names leaking into unrelated error messages) isn't addressed here. Maybe split that into its own issue so it doesn't get closed along with this.

@shiva-istari shiva-istari self-assigned this Sep 1, 2026
@gooohgb

gooohgb commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Hi @shiva-istari, thank you for the review. I’ve addressed the requested cases by adding end-to-end integration coverage for:

Tagged and untagged values in separate mutations, in both orders.

A swap across different languages, which must fail.

A legal swap within the same language, which must succeed.

Duplicate-value errors now include the language-qualified predicate, such as name@en.

I verified the changes against a temporary Zero/Alpha cluster. go test ./edgraph -count=1 and all TestUnique* integration tests passed.

@shiva-istari
shiva-istari force-pushed the fix-unique-lang-identity branch from 26fc117 to 2c3f827 Compare September 3, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

fix(unique): @unique and @lang disagree on whether language is part of value identity

2 participants