Skip to content

Commit cabee91

Browse files
committed
Switch executemany() to execute() for batch inserts
1 parent 2ff13ad commit cabee91

File tree

14 files changed

+67
-21
lines changed

14 files changed

+67
-21
lines changed

README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,49 @@ class Status(str, enum.Enum):
7676
OPEN = "op!en"
7777
CLOSED = "clo@sed"
7878
```
79+
80+
### Bulk Inserts with `:copyfrom`
81+
82+
Use the `:copyfrom` command to generate batch insert methods that leverage SQLAlchemy’s executemany behavior via `Connection.execute()` with a list of parameter mappings.
83+
84+
SQL (example):
85+
86+
```sql
87+
-- name: CreateUsersBatch :copyfrom
88+
INSERT INTO users (email, name) VALUES ($1, $2);
89+
```
90+
91+
Generated methods:
92+
93+
```py
94+
def create_users_batch(self, arg_list: List[Any]) -> int
95+
async def create_users_batch(self, arg_list: List[Any]) -> int
96+
```
97+
98+
Call with a list of dicts using positional parameter keys `p1..pN` (the generator converts `$1`/`@name` to `:pN`):
99+
100+
```py
101+
rows = [
102+
{"p1": "[email protected]", "p2": "Alice"},
103+
{"p1": "[email protected]", "p2": "Bob"},
104+
]
105+
count = queries.create_users_batch(rows) # returns affected rowcount (int)
106+
```
107+
108+
When a typed params struct is emitted (e.g., many parameters or config thresholds), the method accepts `List[<QueryName>Params]`. The generator converts items to dicts internally:
109+
110+
```py
111+
@dataclasses.dataclass()
112+
class CreateUsersWithDetailsParams:
113+
email: str
114+
name: str
115+
bio: Optional[str]
116+
age: Optional[int]
117+
active: Optional[bool]
118+
119+
count = queries.create_users_with_details([
120+
CreateUsersWithDetailsParams("[email protected]", "Alice", None, None, True),
121+
])
122+
```
123+
124+
Implementation note: sync and async use `conn.execute(sqlalchemy.text(SQL), list_of_dicts)` and `await async_conn.execute(...)` respectively; SQLAlchemy performs efficient batch inserts under the hood.

examples/src/authors/query.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def create_author(self, *, name: str, bio: Optional[str]) -> Optional[models.Aut
5858
)
5959

6060
def create_authors_batch(self, arg_list: List[Any]) -> int:
61-
result = self._conn.executemany(sqlalchemy.text(CREATE_AUTHORS_BATCH), arg_list)
61+
result = self._conn.execute(sqlalchemy.text(CREATE_AUTHORS_BATCH), arg_list)
6262
return result.rowcount
6363

6464
def delete_author(self, *, id: int) -> None:
@@ -99,7 +99,7 @@ async def create_author(self, *, name: str, bio: Optional[str]) -> Optional[mode
9999
)
100100

101101
async def create_authors_batch(self, arg_list: List[Any]) -> int:
102-
result = await self._conn.executemany(sqlalchemy.text(CREATE_AUTHORS_BATCH), arg_list)
102+
result = await self._conn.execute(sqlalchemy.text(CREATE_AUTHORS_BATCH), arg_list)
103103
return result.rowcount
104104

105105
async def delete_author(self, *, id: int) -> None:

internal/endtoend/testdata/copyfrom/python/query.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ def create_author(self, *, name: str, bio: str) -> Optional[models.Author]:
6565
)
6666

6767
def create_authors(self, arg_list: List[Any]) -> int:
68-
result = self._conn.executemany(sqlalchemy.text(CREATE_AUTHORS), arg_list)
68+
result = self._conn.execute(sqlalchemy.text(CREATE_AUTHORS), arg_list)
6969
return result.rowcount
7070

7171
def create_authors_named(self, arg_list: List[Any]) -> int:
72-
result = self._conn.executemany(sqlalchemy.text(CREATE_AUTHORS_NAMED), arg_list)
72+
result = self._conn.execute(sqlalchemy.text(CREATE_AUTHORS_NAMED), arg_list)
7373
return result.rowcount
7474

7575
def create_user(self, *, email: str, name: str) -> Optional[models.User]:
@@ -87,7 +87,7 @@ def create_user(self, *, email: str, name: str) -> Optional[models.User]:
8787
)
8888

8989
def create_users_batch(self, arg_list: List[Any]) -> int:
90-
result = self._conn.executemany(sqlalchemy.text(CREATE_USERS_BATCH), arg_list)
90+
result = self._conn.execute(sqlalchemy.text(CREATE_USERS_BATCH), arg_list)
9191
return result.rowcount
9292

9393
def create_users_with_details(self, arg_list: List[CreateUsersWithDetailsParams]) -> int:
@@ -100,7 +100,7 @@ def create_users_with_details(self, arg_list: List[CreateUsersWithDetailsParams]
100100
"p4": item.age,
101101
"p5": item.active,
102102
})
103-
result = self._conn.executemany(sqlalchemy.text(CREATE_USERS_WITH_DETAILS), data)
103+
result = self._conn.execute(sqlalchemy.text(CREATE_USERS_WITH_DETAILS), data)
104104
return result.rowcount
105105

106106

@@ -119,11 +119,11 @@ async def create_author(self, *, name: str, bio: str) -> Optional[models.Author]
119119
)
120120

121121
async def create_authors(self, arg_list: List[Any]) -> int:
122-
result = await self._conn.executemany(sqlalchemy.text(CREATE_AUTHORS), arg_list)
122+
result = await self._conn.execute(sqlalchemy.text(CREATE_AUTHORS), arg_list)
123123
return result.rowcount
124124

125125
async def create_authors_named(self, arg_list: List[Any]) -> int:
126-
result = await self._conn.executemany(sqlalchemy.text(CREATE_AUTHORS_NAMED), arg_list)
126+
result = await self._conn.execute(sqlalchemy.text(CREATE_AUTHORS_NAMED), arg_list)
127127
return result.rowcount
128128

129129
async def create_user(self, *, email: str, name: str) -> Optional[models.User]:
@@ -141,7 +141,7 @@ async def create_user(self, *, email: str, name: str) -> Optional[models.User]:
141141
)
142142

143143
async def create_users_batch(self, arg_list: List[Any]) -> int:
144-
result = await self._conn.executemany(sqlalchemy.text(CREATE_USERS_BATCH), arg_list)
144+
result = await self._conn.execute(sqlalchemy.text(CREATE_USERS_BATCH), arg_list)
145145
return result.rowcount
146146

147147
async def create_users_with_details(self, arg_list: List[CreateUsersWithDetailsParams]) -> int:
@@ -154,5 +154,5 @@ async def create_users_with_details(self, arg_list: List[CreateUsersWithDetailsP
154154
"p4": item.age,
155155
"p5": item.active,
156156
})
157-
result = await self._conn.executemany(sqlalchemy.text(CREATE_USERS_WITH_DETAILS), data)
157+
result = await self._conn.execute(sqlalchemy.text(CREATE_USERS_WITH_DETAILS), data)
158158
return result.rowcount

internal/endtoend/testdata/copyfrom/sqlc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins:
33
- name: py
44
wasm:
55
url: file://../../../../bin/sqlc-gen-python.wasm
6-
sha256: "9aedc973afcc3c089934aaf509843a761e21ac92a4ce34d7a4ba3acebfb49bf0"
6+
sha256: "36baa58bf107df9d93c7fcd9191bf431b9da6bbce754e9ef2d6da3439dbf8a7c"
77
sql:
88
- schema: "schema.sql"
99
queries: "query.sql"

internal/endtoend/testdata/emit_pydantic_models/sqlc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins:
33
- name: py
44
wasm:
55
url: file://../../../../bin/sqlc-gen-python.wasm
6-
sha256: "9aedc973afcc3c089934aaf509843a761e21ac92a4ce34d7a4ba3acebfb49bf0"
6+
sha256: "36baa58bf107df9d93c7fcd9191bf431b9da6bbce754e9ef2d6da3439dbf8a7c"
77
sql:
88
- schema: schema.sql
99
queries: query.sql

internal/endtoend/testdata/emit_str_enum/sqlc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins:
33
- name: py
44
wasm:
55
url: file://../../../../bin/sqlc-gen-python.wasm
6-
sha256: "9aedc973afcc3c089934aaf509843a761e21ac92a4ce34d7a4ba3acebfb49bf0"
6+
sha256: "36baa58bf107df9d93c7fcd9191bf431b9da6bbce754e9ef2d6da3439dbf8a7c"
77
sql:
88
- schema: schema.sql
99
queries: query.sql

internal/endtoend/testdata/exec_result/sqlc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins:
33
- name: py
44
wasm:
55
url: file://../../../../bin/sqlc-gen-python.wasm
6-
sha256: "9aedc973afcc3c089934aaf509843a761e21ac92a4ce34d7a4ba3acebfb49bf0"
6+
sha256: "36baa58bf107df9d93c7fcd9191bf431b9da6bbce754e9ef2d6da3439dbf8a7c"
77
sql:
88
- schema: schema.sql
99
queries: query.sql

internal/endtoend/testdata/exec_rows/sqlc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins:
33
- name: py
44
wasm:
55
url: file://../../../../bin/sqlc-gen-python.wasm
6-
sha256: "9aedc973afcc3c089934aaf509843a761e21ac92a4ce34d7a4ba3acebfb49bf0"
6+
sha256: "36baa58bf107df9d93c7fcd9191bf431b9da6bbce754e9ef2d6da3439dbf8a7c"
77
sql:
88
- schema: schema.sql
99
queries: query.sql

internal/endtoend/testdata/inflection_exclude_table_names/sqlc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins:
33
- name: py
44
wasm:
55
url: file://../../../../bin/sqlc-gen-python.wasm
6-
sha256: "9aedc973afcc3c089934aaf509843a761e21ac92a4ce34d7a4ba3acebfb49bf0"
6+
sha256: "36baa58bf107df9d93c7fcd9191bf431b9da6bbce754e9ef2d6da3439dbf8a7c"
77
sql:
88
- schema: schema.sql
99
queries: query.sql

internal/endtoend/testdata/query_parameter_limit_two/sqlc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins:
33
- name: py
44
wasm:
55
url: file://../../../../bin/sqlc-gen-python.wasm
6-
sha256: "9aedc973afcc3c089934aaf509843a761e21ac92a4ce34d7a4ba3acebfb49bf0"
6+
sha256: "36baa58bf107df9d93c7fcd9191bf431b9da6bbce754e9ef2d6da3439dbf8a7c"
77
sql:
88
- schema: schema.sql
99
queries: query.sql

0 commit comments

Comments
 (0)