Skip to content

Conversation

puzzledpolymath
Copy link
Contributor

@puzzledpolymath puzzledpolymath commented Jul 11, 2025

This pull request adds support for performing upsert queries. Ticket #50 is what sparked interest for this feature.

🔍 What was changed

  • Each driver (MySQL, Postgres, SQLite and SQLServer) compiler supports an UpsertQuery.
  • Differences between SQL dialects have been accounted for.

🤔 Why?

  1. Upsert allows developers to combine insert and update operations into a single command, reducing the need for explicit existence checks and multiple database calls.
  2. Modern databases support atomic upsert operations, which help maintain data integrity even in concurrent environments.
  3. Upsert reduces the number of database round-trips, eliminating separate existence checks followed by insert or update, likely leading to better performance, especially in high-volume scenarios.

📝 Checklist

📃 Documentation

Note that specifying conflict index column names is redundant and not required for MySQL.

PHP

$upsert = $this->database->upsert('users')
    ->conflicts('email')
    ->columns('email', 'name')
    ->values('[email protected]', 'Adam')
    ->values('[email protected]', 'Bill');
$upsert = $this->database->upsert('users')
    ->conflicts(['email'])
    ->values([
        ['email' => '[email protected]', 'name' => 'Adam'],
        ['email' => '[email protected]', 'name' => 'Bill'],
    ]);

MySQL

INSERT INTO `users` (`email`, `name`)
VALUES
    ('[email protected]', 'Adam'),
    ('[email protected]', 'Bill')
ON DUPLICATE KEY UPDATE
    `email` = VALUES(`email`),
    `name` = VALUES(`name`);

Postgres / SQLite

INSERT INTO `users` (`email`, `name`)
VALUES
    ('[email protected]', 'Adam'),
    ('[email protected]', 'Bill')
ON CONFLICT (`email`) DO UPDATE SET
    `email` = EXCLUDED.`email`,
    `name` = EXCLUDED.`name`

MSSQL

MERGE INTO [users] WITH (holdlock) AS [target] 
USING ( VALUES 
    ('[email protected]', 'Adam'),
    ('[email protected]', 'Bill') 
) AS [source] ([email], [name]) 
ON [target].[email] = [source].[email] 
WHEN MATCHED THEN 
    UPDATE SET 
        [target].[email] = [source].[email], 
        [target].[name] = [source].[name] 
WHEN NOT MATCHED THEN 
    INSERT ([email], [name]) 
    VALUES ([source].[email], [source].[name])

@cycle cycle deleted a comment from codecov bot Jul 11, 2025
@puzzledpolymath puzzledpolymath requested a review from a team as a code owner July 11, 2025 07:19
@cycle cycle deleted a comment from codecov bot Jul 11, 2025
@cycle cycle deleted a comment from codecov bot Jul 11, 2025
@cycle cycle deleted a comment from codecov bot Jul 11, 2025
Copy link

codecov bot commented Jul 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.61%. Comparing base (3d7ee35) to head (c53a6f0).

Additional details and impacted files
@@             Coverage Diff              @@
##                2.x     #231      +/-   ##
============================================
+ Coverage     95.42%   95.61%   +0.19%     
- Complexity     1896     1957      +61     
============================================
  Files           131      134       +3     
  Lines          5285     5523     +238     
============================================
+ Hits           5043     5281     +238     
  Misses          242      242              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@puzzledpolymath puzzledpolymath mentioned this pull request Jul 11, 2025
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

💡 Add support for MySQL: ON DUPLICATE KEY UPDATE, PostgreSQL: ON CONFLICT
1 participant