From 4a3a64920165e328c0ebbdb55ea515f3ac5747af Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Thu, 18 Jun 2026 19:50:17 -0700 Subject: [PATCH 1/6] feat(orm): add Model.insert() classmethod for bulk inserts Add an async insert() classmethod that delegates to the query builder, supporting a single dict or a list of dicts. Unlike create(), it does not fire model events, apply timestamps, or instantiate models, making it suitable for high-volume seed and batch operations. Includes tests covering single-row and bulk classmethod inserts. --- .../fastapi_startkit/masoniteorm/models/model.py | 15 +++++++++++++++ .../sqlite/builder/test_sqlite_builder_insert.py | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py index 2e6d377f..3beda2e7 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py @@ -316,6 +316,21 @@ async def create(cls, attributes: dict): return instance + @classmethod + async def insert(cls, values): + """Bulk-insert one or many rows without instantiating model instances. + + Unlike `create`, this does NOT fire model events, apply timestamps, + or return model instances. Use for high-volume seed/batch operations. + + Args: + values: A single dict OR a list of dicts, each representing a row. + + Returns: + The number of rows inserted (driver-dependent), or None. + """ + return await cls.query().insert(values) + async def update(self, attributes: dict) -> bool: if not self._exists: return False diff --git a/fastapi_startkit/tests/masoniteorm/sqlite/builder/test_sqlite_builder_insert.py b/fastapi_startkit/tests/masoniteorm/sqlite/builder/test_sqlite_builder_insert.py index 8b843b1b..51b18741 100644 --- a/fastapi_startkit/tests/masoniteorm/sqlite/builder/test_sqlite_builder_insert.py +++ b/fastapi_startkit/tests/masoniteorm/sqlite/builder/test_sqlite_builder_insert.py @@ -38,3 +38,17 @@ async def test_bulk_insert_sql_multiple(self): sql, bindings = mock_insert.call_args[0] self.assertEqual(sql, 'INSERT INTO "users" ("name") VALUES (?), (?), (?)') self.assertEqual(list(bindings), ["Joe", "Bill", "John"]) + + async def test_insert_classmethod_single_row(self): + await User.insert({"email": "classmethod@test.com", "name": "CM User", "is_admin": False}) + user = await User.where("email", "classmethod@test.com").first() + assert user is not None + assert user.name == "CM User" + + async def test_insert_classmethod_bulk_rows(self): + mock_insert = AsyncMock(return_value=2) + DB.connection("sqlite").insert = mock_insert + await User.insert([{"name": "Alice"}, {"name": "Bob"}]) + mock_insert.assert_called_once() + sql, bindings = mock_insert.call_args[0] + self.assertIn('INSERT INTO', sql) From e22f6d5b62361e081280ba4a9960f668bc2d7561 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Thu, 18 Jun 2026 19:52:26 -0700 Subject: [PATCH 2/6] test(orm): add postgres model tests for Model.insert() Cover single-row and bulk insert via the new insert() classmethod against the postgres integration test suite. --- .../masoniteorm/postgres/models/test_model.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/fastapi_startkit/tests/masoniteorm/postgres/models/test_model.py b/fastapi_startkit/tests/masoniteorm/postgres/models/test_model.py index 0595cef2..ff971ff5 100644 --- a/fastapi_startkit/tests/masoniteorm/postgres/models/test_model.py +++ b/fastapi_startkit/tests/masoniteorm/postgres/models/test_model.py @@ -133,3 +133,22 @@ async def test_count_returns_correct_number(self): count = await User.count() self.assertEqual(count, 2) + + async def test_insert_single_row(self): + await User.insert({"name": "Olivia", "email": "olivia@example.com", "is_admin": False}) + + user = await User.where("email", "olivia@example.com").first() + self.assertIsNotNone(user) + self.assertEqual(user.name, "Olivia") + + async def test_insert_bulk_rows(self): + await User.insert([ + {"name": "Peggy", "email": "peggy@example.com", "is_admin": False}, + {"name": "Quentin", "email": "quentin@example.com", "is_admin": True}, + ]) + + count = await User.count() + self.assertEqual(count, 2) + + admin = await User.where("is_admin", True).first() + self.assertEqual(admin.name, "Quentin") From 8222767580940b08725e809e932d3733441a4bee Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Thu, 18 Jun 2026 19:54:50 -0700 Subject: [PATCH 3/6] refactor(orm): type insert() signature and drop docstring --- .../fastapi_startkit/masoniteorm/models/model.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py index 3beda2e7..aee8dfaa 100644 --- a/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py +++ b/fastapi_startkit/src/fastapi_startkit/masoniteorm/models/model.py @@ -317,18 +317,7 @@ async def create(cls, attributes: dict): return instance @classmethod - async def insert(cls, values): - """Bulk-insert one or many rows without instantiating model instances. - - Unlike `create`, this does NOT fire model events, apply timestamps, - or return model instances. Use for high-volume seed/batch operations. - - Args: - values: A single dict OR a list of dicts, each representing a row. - - Returns: - The number of rows inserted (driver-dependent), or None. - """ + async def insert(cls, values: dict | list) -> int | None: return await cls.query().insert(values) async def update(self, attributes: dict) -> bool: From e956c6ce1ce499f633bbe10ae02778727c98eb15 Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Thu, 18 Jun 2026 19:59:12 -0700 Subject: [PATCH 4/6] test(orm): assert exact SQL and bindings in bulk insert classmethod test --- .../masoniteorm/sqlite/builder/test_sqlite_builder_insert.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fastapi_startkit/tests/masoniteorm/sqlite/builder/test_sqlite_builder_insert.py b/fastapi_startkit/tests/masoniteorm/sqlite/builder/test_sqlite_builder_insert.py index 51b18741..c04c53f1 100644 --- a/fastapi_startkit/tests/masoniteorm/sqlite/builder/test_sqlite_builder_insert.py +++ b/fastapi_startkit/tests/masoniteorm/sqlite/builder/test_sqlite_builder_insert.py @@ -51,4 +51,5 @@ async def test_insert_classmethod_bulk_rows(self): await User.insert([{"name": "Alice"}, {"name": "Bob"}]) mock_insert.assert_called_once() sql, bindings = mock_insert.call_args[0] - self.assertIn('INSERT INTO', sql) + self.assertEqual(sql, 'INSERT INTO "users" ("name") VALUES (?), (?)') + self.assertEqual(list(bindings), ["Alice", "Bob"]) From 6c94613d5d81a1337aedad02db49ff41f1dc8dec Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Thu, 18 Jun 2026 20:00:58 -0700 Subject: [PATCH 5/6] style: apply ruff format to postgres insert test --- .../tests/masoniteorm/postgres/models/test_model.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fastapi_startkit/tests/masoniteorm/postgres/models/test_model.py b/fastapi_startkit/tests/masoniteorm/postgres/models/test_model.py index ff971ff5..b5a48c57 100644 --- a/fastapi_startkit/tests/masoniteorm/postgres/models/test_model.py +++ b/fastapi_startkit/tests/masoniteorm/postgres/models/test_model.py @@ -142,10 +142,12 @@ async def test_insert_single_row(self): self.assertEqual(user.name, "Olivia") async def test_insert_bulk_rows(self): - await User.insert([ - {"name": "Peggy", "email": "peggy@example.com", "is_admin": False}, - {"name": "Quentin", "email": "quentin@example.com", "is_admin": True}, - ]) + await User.insert( + [ + {"name": "Peggy", "email": "peggy@example.com", "is_admin": False}, + {"name": "Quentin", "email": "quentin@example.com", "is_admin": True}, + ] + ) count = await User.count() self.assertEqual(count, 2) From a2ca74c42b6a0dbfda83c7a42a46660366be4dce Mon Sep 17 00:00:00 2001 From: Bedram Tamang Date: Thu, 18 Jun 2026 20:08:27 -0700 Subject: [PATCH 6/6] style: apply ruff format to postgres insert grammar test --- .../postgres/grammar/test_postgres_insert_grammar.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fastapi_startkit/tests/masoniteorm/postgres/grammar/test_postgres_insert_grammar.py b/fastapi_startkit/tests/masoniteorm/postgres/grammar/test_postgres_insert_grammar.py index 382daf0d..da3eb178 100644 --- a/fastapi_startkit/tests/masoniteorm/postgres/grammar/test_postgres_insert_grammar.py +++ b/fastapi_startkit/tests/masoniteorm/postgres/grammar/test_postgres_insert_grammar.py @@ -27,8 +27,7 @@ def test_compile_bulk_create_builds_multi_row_insert(self): self.assertEqual( sql, - 'INSERT INTO "users" ("name", "email") VALUES ' - "('Joe', 'joe@example.com'), ('Bob', 'bob@example.com')", + "INSERT INTO \"users\" (\"name\", \"email\") VALUES ('Joe', 'joe@example.com'), ('Bob', 'bob@example.com')", )