Skip to content

Improve InsertQuery with IGNORE and flexible ON CONFLICT#148

Closed
cungminh2710 wants to merge 2 commits into
mainfrom
feat/insert-improvements-6210615493842366896
Closed

Improve InsertQuery with IGNORE and flexible ON CONFLICT#148
cungminh2710 wants to merge 2 commits into
mainfrom
feat/insert-improvements-6210615493842366896

Conversation

@cungminh2710

Copy link
Copy Markdown
Contributor

This change enhances Rain ORM's InsertQuery to achieve better parity with Drizzle ORM.

Key improvements:

  1. MySQL INSERT IGNORE: Added an .Ignore() method and updated the compiler to emit INSERT IGNORE for MySQL.
  2. PostgreSQL/SQLite ON CONFLICT DO NOTHING: Removed the requirement for at least one conflict target when the action is DO NOTHING, matching standard SQL behavior for these dialects.
  3. Flexible Conflict Targets: Updated OnConflict to accept ...schema.Expression instead of just columns. This allows targeting functional indexes (e.g., OnConflict(schema.Raw("(lower(email))"))).
  4. Dialect-aware Ergonomics: Calling .OnConflict().DoNothing() on a MySQL dialect now automatically utilizes INSERT IGNORE logic, providing a consistent API across dialects.

Verified with comprehensive unit tests for PostgreSQL and MySQL dialects.


PR created automatically by Jules for task 6210615493842366896 started by @cungminh2710

- Implement MySQL `INSERT IGNORE` support via `.Ignore()`.
- Map `OnConflict().DoNothing()` to `INSERT IGNORE` for MySQL.
- Allow `OnConflict().DoNothing()` without targets for PostgreSQL and SQLite.
- Support `schema.Expression` in `OnConflict` targets for functional indexes.
- Ensure non-column expressions in conflict targets are wrapped in parentheses.
- Add comprehensive tests for the new insertion behaviors.

Co-authored-by: cungminh2710 <8063319+cungminh2710@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR expands insert conflict handling across dialects. The main changes are:

  • Adds MySQL INSERT IGNORE support through Ignore().
  • Maps MySQL OnConflict().DoNothing() to INSERT IGNORE.
  • Allows targetless ON CONFLICT DO NOTHING for PostgreSQL and SQLite.
  • Allows expression-based conflict targets for functional indexes.
  • Adds tests for the new insert conflict paths.

Confidence Score: 5/5

This looks safe to merge from this follow-up review.

  • No blocking issues found in the changed code that are separate from the existing review threads.

Important Files Changed

Filename Overview
pkg/rain/query_insert.go Updates insert compilation for ignore mode, targetless conflict handling, and expression conflict targets.
pkg/rain/query_insert_test.go Adds coverage for MySQL ignore inserts, targetless conflict handling, and functional conflict targets.

Reviews (2): Last reviewed commit: "feat(rain): improve InsertQuery with IGN..." | Re-trigger Greptile

Comment thread pkg/rain/query_insert.go
Comment on lines +729 to +730
if q.conflict.action == insertConflictActionDoNothing {
return nil

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.

P1 Scoped Conflicts Become Global Ignore

When a MySQL caller uses OnConflict(users.Email).Where(...).DoNothing() or OnConstraint(...).DoNothing(), this branch returns before rejecting the unsupported target fields and the compiler emits plain INSERT IGNORE. That drops the requested conflict scope and can silently ignore unrelated duplicate-key, NOT NULL, foreign-key, or data conversion errors instead of returning them.

Context Used: AGENTS.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/rain/query_insert.go
Line: 729-730

Comment:
**Scoped Conflicts Become Global Ignore**

When a MySQL caller uses `OnConflict(users.Email).Where(...).DoNothing()` or `OnConstraint(...).DoNothing()`, this branch returns before rejecting the unsupported target fields and the compiler emits plain `INSERT IGNORE`. That drops the requested conflict scope and can silently ignore unrelated duplicate-key, NOT NULL, foreign-key, or data conversion errors instead of returning them.

**Context Used:** AGENTS.md ([source](https://app.greptile.com/hyperlocalise/github/hyperlocalise/rain-orm/-/custom-context?memory=3b24bd19-4fb7-4328-8fc3-52795c121ec6))

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex

Comment thread pkg/rain/query_insert.go
defer releaseCompileContext(ctx)

if q.dialect.Name() == "mysql" && q.conflict != nil && q.conflict.action == insertConflictActionDoNothing {
q.ignore = true

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.

P2 Compilation Persists Ignore State

ToSQL, Exec, and Prepare now mutate the builder by setting q.ignore when MySQL DoNothing is compiled. If the same InsertQuery is compiled once for DoNothing and then reused with a different conflict action, the stale flag still emits INSERT IGNORE, so a later DoUpdateSet query can compile as INSERT IGNORE ... ON DUPLICATE KEY UPDATE ... without the caller asking for ignore semantics.

Context Used: AGENTS.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/rain/query_insert.go
Line: 272

Comment:
**Compilation Persists Ignore State**

`ToSQL`, `Exec`, and `Prepare` now mutate the builder by setting `q.ignore` when MySQL `DoNothing` is compiled. If the same `InsertQuery` is compiled once for `DoNothing` and then reused with a different conflict action, the stale flag still emits `INSERT IGNORE`, so a later `DoUpdateSet` query can compile as `INSERT IGNORE ... ON DUPLICATE KEY UPDATE ...` without the caller asking for ignore semantics.

**Context Used:** AGENTS.md ([source](https://app.greptile.com/hyperlocalise/github/hyperlocalise/rain-orm/-/custom-context?memory=3b24bd19-4fb7-4328-8fc3-52795c121ec6))

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex

Comment thread pkg/rain/query_insert.go
Comment on lines +790 to +792
ctx.writeColumnName(col)
} else {
if err := ctx.writeExpression(target); err != nil {

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.

P2 Conflict Targets Accept Parameters

Non-column conflict targets are rendered with the general expression writer, which can add bind parameters for expressions such as schema.Raw("lower(email COLLATE ?)", locale), placeholders, values, comparisons, or subqueries. PostgreSQL and SQLite conflict targets must name columns or index expressions, so this can return SQL like ON CONFLICT (lower(email COLLATE $2)) with an extra argument that the database rejects instead of failing during query construction.

Context Used: AGENTS.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/rain/query_insert.go
Line: 790-792

Comment:
**Conflict Targets Accept Parameters**

Non-column conflict targets are rendered with the general expression writer, which can add bind parameters for expressions such as `schema.Raw("lower(email COLLATE ?)", locale)`, placeholders, values, comparisons, or subqueries. PostgreSQL and SQLite conflict targets must name columns or index expressions, so this can return SQL like `ON CONFLICT (lower(email COLLATE $2))` with an extra argument that the database rejects instead of failing during query construction.

**Context Used:** AGENTS.md ([source](https://app.greptile.com/hyperlocalise/github/hyperlocalise/rain-orm/-/custom-context?memory=3b24bd19-4fb7-4328-8fc3-52795c121ec6))

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex

- Implement MySQL `INSERT IGNORE` support via `.Ignore()`.
- Map `OnConflict().DoNothing()` to `INSERT IGNORE` for MySQL.
- Allow `OnConflict().DoNothing()` without targets for PostgreSQL and SQLite.
- Support `schema.Expression` in `OnConflict` targets for functional indexes.
- Ensure non-column expressions in conflict targets are correctly rendered.
- Add comprehensive tests for the new insertion behaviors.

Co-authored-by: cungminh2710 <8063319+cungminh2710@users.noreply.github.com>
Sign up for free to 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.

1 participant