-
Notifications
You must be signed in to change notification settings - Fork 101
Open
Labels
Adopter Requested Feature/DocumentationblockedenhancementAdding new features or extending existing capabilitiesAdding new features or extending existing capabilitiesimprovementMaking something that already exists betterMaking something that already exists betterrequestedRequested by an adopter or userRequested by an adopter or user
Description
Problem
Right now upsertUnique always mutates, meaning user modifications will be overwritten if the record exists.
There are common cases where the intended semantics are instead: create the record if it doesn’t exist, but if it does exist, just return it unchanged.
Option 1: Separate method
const learnJazzTask = await Task.getOrCreateUnique({
value: {
text: "Let's learn some Jazz!",
},
unique: "learning-jazz",
owner: project.$jazz.owner,
});Pros
- Very explicit about semantics.
- Matches naming conventions in other ORMs (
getOrCreate,findOrCreate). - Keeps
upsertUniquenarrowly focused.
Cons
- Duplicates a lot of
upsertUniqueimplementation. - Naming is a bit unwieldy (
getOrCreateUnique).
Option 2: Extend upsertUnique with a flag
const learnJazzTask = await Task.upsertUnique({
value: {
text: "Let's learn some Jazz!",
},
unique: "learning-jazz",
owner: project.$jazz.owner,
ifExists: "overwrite", // "overwrite" | "return" - defautlt 'overwrite'
});Pros
- Reuses existing API surface — no new top-level method.
- Reduces code duplication internally.
- Easier to document and maintain one concept instead of two.
Cons
- Semantics are less immediately clear:
upsertUniqueis now doing two quite different things depending on an option. - Risk of confusion between “update-or-insert” vs. “insert-or-return.”
Option 3: Provide a thin alias (getOrCreateUnique)
const learnJazzTask = await Task.getOrCreate({
value: {
text: "Let's learn some Jazz!",
},
unique: "learning-jazz",
owner: project.$jazz.owner,
});Under the hood this would simply call:
Task.upsertUnique({ ..., ifExists: "return" });Pros
- Clearer semantics than Option 2.
- Minimal implementation cost (just syntactic sugar).
- Avoids code duplication (unlike Option 1).
Cons
- Adds another method name to the API surface, which can cause slight cognitive overhead.
- Still means implementing Option 2, but 'hiding it' behind a different API.
Metadata
Metadata
Assignees
Labels
Adopter Requested Feature/DocumentationblockedenhancementAdding new features or extending existing capabilitiesAdding new features or extending existing capabilitiesimprovementMaking something that already exists betterMaking something that already exists betterrequestedRequested by an adopter or userRequested by an adopter or user