feat(orm): Eloquent-style upsert() on the async Masonite ORM#129
Closed
bedus-creation wants to merge 1 commit into
Closed
feat(orm): Eloquent-style upsert() on the async Masonite ORM#129bedus-creation wants to merge 1 commit into
bedus-creation wants to merge 1 commit into
Conversation
Add upsert() on both Model and AsyncQueryBuilder. Rows are inserted in a single bulk statement; on a unique_by collision the listed columns are updated (all non-unique columns when update is omitted). SQL is dialect-specific via SQLAlchemy dialect insert helpers: - Postgres/SQLite: INSERT ... ON CONFLICT (unique_by) DO UPDATE SET col = excluded.col - MySQL: INSERT ... ON DUPLICATE KEY UPDATE col = VALUES(col) Values are normalised to a shared column set and run through the model's casters, consistent with existing insert paths.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a Laravel/Eloquent-style
upsert()to the async Masonite ORM, exposed on both theModel(classmethod) and theAsyncQueryBuilder, mirroring howcreate()/ bulkinsert()are exposed today.unique_bycolumns, UPDATEs only the columns inupdate.updateis omitted, all non-unique columns are updated (Laravel behaviour).unique_by/updateaccept a string or list.0for empty input.Dialect-specific SQL
Built with SQLAlchemy's dialect insert helpers so each driver gets the correct clause:
INSERT ... ON CONFLICT (unique_by) DO UPDATE SET col = excluded.colINSERT ... ON CONFLICT (unique_by) DO UPDATE SET col = excluded.colINSERT ... ON DUPLICATE KEY UPDATE col = VALUES(col)When the resolved update set is empty, it degrades to
DO NOTHING(Postgres/SQLite) or a no-op key update (MySQL).Implementation
masoniteorm/query/upsert.py—build_upsert_statement()picks the dialect insert helper from the connection driver and builds one bulk statement over a lightweightsqlalchemy.table(...).QueryBuilder.upsert()— normalises rows to a shared, deterministic column set and runs values through the model's casters (consistent with existing insert paths), then executes the construct.Connection.execute_statement()— executes a SQLAlchemy core construct directly (commits when not inside a transaction), since upsert SQL is built with dialect helpers rather than the grammar.Model.upsert()— classmethod delegating to the builder.Tests
tests/masoniteorm/sqlite/builder/test_sqlite_builder_upsert.py— end-to-end against SQLite: insert-only, single dict, update-on-conflict without duplicating,update-list restriction, default (all non-unique) update, mixed insert+update in one call, empty input.tests/masoniteorm/test_upsert_statement.py— compiles the statement for Postgres, SQLite and MySQL and asserts the exact dialect clause + single bulk INSERT.Full ORM suite (excluding live Postgres/MySQL): 386 passed, 7 skipped. New tests: 13 passed.