Skip to content

Commit d2caf58

Browse files
committed
feat: bulk_update_with_fly_table
1 parent ff2e35a commit d2caf58

File tree

5 files changed

+407
-9
lines changed

5 files changed

+407
-9
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,27 @@ Generate sql and execute
129129
SELECT gender, locale, False active, CONCAT(LEFT(name, 26), ' [NEW]') name, '{}' extend
130130
FROM account
131131
WHERE id IN (4, 5, 6)
132-
```
132+
```
133+
134+
### **bulk_update_with_fly_table**
135+
```python
136+
await AccountMgr.bulk_update_with_fly_table(
137+
[
138+
{'id': 7, 'active': False, 'gender': <GenderEnum.male: 1>},
139+
{'id': 15, 'active': True, 'gender': <GenderEnum.unknown: 0>}
140+
],
141+
join_fields=["id"],
142+
update_fields=["active", "gender"],
143+
)
144+
```
145+
Generate sql and execute
146+
```sql
147+
UPDATE account
148+
JOIN (
149+
SELECT * FROM (
150+
VALUES
151+
ROW(7, False, 1), ROW(15, True, 0)
152+
) AS fly_table (id, active, gender)
153+
) tmp ON account.id = tmp.id
154+
SET account.active = tmp.active, account.gender = tmp.gender
155+
```
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
{
2+
"info": {
3+
"_postman_id": "ca623517-c9e2-44b5-9bbf-bb6c8157ab67",
4+
"name": "fastapi-efficient-sql",
5+
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6+
},
7+
"item": [
8+
{
9+
"name": "/account/create",
10+
"request": {
11+
"method": "POST",
12+
"header": [],
13+
"url": {
14+
"raw": "{{local}}:8000/api/account/create",
15+
"host": [
16+
"{{local}}"
17+
],
18+
"port": "8000",
19+
"path": [
20+
"api",
21+
"account",
22+
"create"
23+
]
24+
}
25+
},
26+
"response": []
27+
},
28+
{
29+
"name": "/account/update",
30+
"request": {
31+
"method": "POST",
32+
"header": [],
33+
"url": {
34+
"raw": "{{local}}:8000/api/account/update?aid=7",
35+
"host": [
36+
"{{local}}"
37+
],
38+
"port": "8000",
39+
"path": [
40+
"api",
41+
"account",
42+
"update"
43+
],
44+
"query": [
45+
{
46+
"key": "aid",
47+
"value": "7"
48+
}
49+
]
50+
}
51+
},
52+
"response": []
53+
},
54+
{
55+
"name": "/account/query/by_id",
56+
"request": {
57+
"method": "GET",
58+
"header": [],
59+
"url": {
60+
"raw": "{{local}}:8000/api/account/query/by_id?aid=10",
61+
"host": [
62+
"{{local}}"
63+
],
64+
"port": "8000",
65+
"path": [
66+
"api",
67+
"account",
68+
"query",
69+
"by_id"
70+
],
71+
"query": [
72+
{
73+
"key": "aid",
74+
"value": "10"
75+
}
76+
]
77+
}
78+
},
79+
"response": []
80+
},
81+
{
82+
"name": "/account/query/group_by_locale",
83+
"request": {
84+
"method": "POST",
85+
"header": [],
86+
"url": {
87+
"raw": "{{local}}:8000/api/account/query/group_by_locale",
88+
"host": [
89+
"{{local}}"
90+
],
91+
"port": "8000",
92+
"path": [
93+
"api",
94+
"account",
95+
"query",
96+
"group_by_locale"
97+
]
98+
}
99+
},
100+
"response": []
101+
},
102+
{
103+
"name": "/account/bulk_init",
104+
"request": {
105+
"method": "POST",
106+
"header": [],
107+
"url": {
108+
"raw": "{{local}}:8000/api/account/bulk_init",
109+
"host": [
110+
"{{local}}"
111+
],
112+
"port": "8000",
113+
"path": [
114+
"api",
115+
"account",
116+
"bulk_init"
117+
]
118+
}
119+
},
120+
"response": []
121+
},
122+
{
123+
"name": "/account/last_login/query",
124+
"request": {
125+
"method": "POST",
126+
"header": [],
127+
"body": {
128+
"mode": "raw",
129+
"raw": "{\n \"aids\": [1, 2, 3]\n}",
130+
"options": {
131+
"raw": {
132+
"language": "json"
133+
}
134+
}
135+
},
136+
"url": {
137+
"raw": "{{local}}:8000/api/account/last_login/query",
138+
"host": [
139+
"{{local}}"
140+
],
141+
"port": "8000",
142+
"path": [
143+
"api",
144+
"account",
145+
"last_login",
146+
"query"
147+
]
148+
}
149+
},
150+
"response": []
151+
},
152+
{
153+
"name": "/account/last_login/update",
154+
"request": {
155+
"method": "POST",
156+
"header": [],
157+
"url": {
158+
"raw": "{{local}}:8000/api/account/last_login/update?account_id=8",
159+
"host": [
160+
"{{local}}"
161+
],
162+
"port": "8000",
163+
"path": [
164+
"api",
165+
"account",
166+
"last_login",
167+
"update"
168+
],
169+
"query": [
170+
{
171+
"key": "account_id",
172+
"value": "8"
173+
}
174+
]
175+
}
176+
},
177+
"response": []
178+
},
179+
{
180+
"name": "/account/bulk_upsert",
181+
"request": {
182+
"method": "POST",
183+
"header": [],
184+
"url": {
185+
"raw": "{{local}}:8000/api/account/bulk_upsert",
186+
"host": [
187+
"{{local}}"
188+
],
189+
"port": "8000",
190+
"path": [
191+
"api",
192+
"account",
193+
"bulk_upsert"
194+
]
195+
}
196+
},
197+
"response": []
198+
},
199+
{
200+
"name": "/account/bulk_clone",
201+
"request": {
202+
"method": "POST",
203+
"header": [],
204+
"body": {
205+
"mode": "raw",
206+
"raw": "{\n \"account_ids\": [4, 5, 6]\n}",
207+
"options": {
208+
"raw": {
209+
"language": "json"
210+
}
211+
}
212+
},
213+
"url": {
214+
"raw": "{{local}}:8000/api/account/bulk_clone",
215+
"host": [
216+
"{{local}}"
217+
],
218+
"port": "8000",
219+
"path": [
220+
"api",
221+
"account",
222+
"bulk_clone"
223+
]
224+
}
225+
},
226+
"response": []
227+
},
228+
{
229+
"name": "/account/bulk_update",
230+
"request": {
231+
"method": "POST",
232+
"header": [],
233+
"body": {
234+
"mode": "raw",
235+
"raw": "{\n \"dicts\": [\n {\"id\": 7, \"active\": false, \"gender\": 1},\n {\"id\": 15, \"active\": true, \"gender\": 0}\n ]\n}",
236+
"options": {
237+
"raw": {
238+
"language": "json"
239+
}
240+
}
241+
},
242+
"url": {
243+
"raw": "{{local}}:8000/api/account/bulk_update",
244+
"host": [
245+
"{{local}}"
246+
],
247+
"port": "8000",
248+
"path": [
249+
"api",
250+
"account",
251+
"bulk_update"
252+
]
253+
}
254+
},
255+
"response": []
256+
},
257+
{
258+
"name": "/basic/ping",
259+
"request": {
260+
"method": "GET",
261+
"header": [],
262+
"url": {
263+
"raw": "{{local}}:8000/api/basic/ping",
264+
"host": [
265+
"{{local}}"
266+
],
267+
"port": "8000",
268+
"path": [
269+
"api",
270+
"basic",
271+
"ping"
272+
]
273+
}
274+
},
275+
"response": []
276+
},
277+
{
278+
"name": "/basic/background/sleep",
279+
"request": {
280+
"method": "GET",
281+
"header": [],
282+
"url": {
283+
"raw": "{{local}}:8000/api/basic/background/sleep",
284+
"host": [
285+
"{{local}}"
286+
],
287+
"port": "8000",
288+
"path": [
289+
"api",
290+
"basic",
291+
"background",
292+
"sleep"
293+
]
294+
}
295+
},
296+
"response": []
297+
}
298+
]
299+
}

examples/service/routers/account.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
from faker import Faker
55
from fastapi import APIRouter, Body, Query
66
from fastapi_esql.utils.sqlizer import RawSQL
7+
from pydantic import BaseModel, Field
78

8-
from examples.service.constants.enums import LocaleEnum
9+
from examples.service.constants.enums import GenderEnum, LocaleEnum
910
from examples.service.managers.demo.account import AccountMgr
1011

1112
router = APIRouter()
@@ -146,7 +147,7 @@ async def bulk_upsert_view():
146147

147148

148149
@router.post("/bulk_clone")
149-
async def clone_account_view(
150+
async def bulk_clone_view(
150151
aids: List[int] = Body(..., embed=True),
151152
):
152153
ok = await AccountMgr.insert_into_select(
@@ -159,3 +160,20 @@ async def clone_account_view(
159160
},
160161
)
161162
return {"ok": ok}
163+
164+
165+
class UpdateIn(BaseModel):
166+
id: int = Field(...)
167+
active: bool = Field(...)
168+
gender: GenderEnum = Field(...)
169+
170+
@router.post("/bulk_update")
171+
async def bulk_update_view(
172+
dicts: List[UpdateIn] = Body(..., embed=True),
173+
):
174+
row_cnt = await AccountMgr.bulk_update_with_fly_table(
175+
[d.dict() for d in dicts],
176+
join_fields=["id"],
177+
update_fields=["active", "gender"],
178+
)
179+
return {"row_cnt": row_cnt}

fastapi_esql/orm/base_manager.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,18 @@ async def insert_into_select(
120120
assign_field_dict,
121121
)
122122
return await CursorHandler.exec_if_ok(sql, cls.rw_conn, logger)
123+
124+
@classmethod
125+
async def bulk_update_with_fly_table(
126+
cls,
127+
dicts: List[Dict[str, Any]],
128+
join_fields: List[str],
129+
update_fields: List[str],
130+
):
131+
sql = SQLizer.bulk_update_with_fly_table(
132+
cls.table,
133+
dicts,
134+
join_fields,
135+
update_fields,
136+
)
137+
return await CursorHandler.calc_row_cnt(sql, cls.rw_conn, logger)

0 commit comments

Comments
 (0)