Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/ja/reference/framework-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,29 @@ rows = executor.fetch_all("SELECT * FROM notes WHERE id = :id", {"id": 1})
executor.write("INSERT INTO notes (title, body) VALUES (:t, :b)", {"t": "t", "b": "b"})
```

#### `write()` の返り値

| 操作 | 返り値 |
|---|---|
| `AUTOINCREMENT` / `SERIAL` 付き `INSERT` | `lastrowid` — 新規行の主キー(常に > 0) |
| auto-PK なし、またはマルチ行 `INSERT` | `rowcount` — 挿入行数 |
| `UPDATE` / `DELETE` | `rowcount` — 影響行数(0 は該当なし) |

INSERT 後にエンティティを再構築する場合:

```python
new_id = executor.write("INSERT INTO notes (title) VALUES (:title)", {"title": "Hello"})
return Note(id=new_id, title="Hello")
```

UPDATE / DELETE で存在しないリソースを検出する場合:

```python
affected = executor.write("UPDATE notes SET title=:title WHERE id=:id", {"title": t, "id": pk})
if affected == 0:
raise NoteNotFoundException(pk)
```

### `SqlAlchemyTransactionManager`

トランザクションを管理します。手動の `begin/commit/rollback` より `transactional()` を推奨します。
Expand Down
25 changes: 25 additions & 0 deletions docs/reference/framework-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,31 @@ rows = executor.fetch_all("SELECT * FROM notes WHERE id = :id", {"id": 1})
executor.write("INSERT INTO notes (title, body) VALUES (:t, :b)", {"t": "t", "b": "b"})
```

#### `write()` return value

`write()` returns an `int` whose meaning depends on the SQL operation:

| Operation | Return value |
|---|---|
| `INSERT` with `AUTOINCREMENT` / `SERIAL` | `lastrowid` — the new row's primary key (always > 0) |
| `INSERT` without auto-PK, or multi-row `INSERT` | `rowcount` — number of rows inserted |
| `UPDATE` / `DELETE` | `rowcount` — rows affected (0 if nothing matched) |

Use `lastrowid` to reconstruct the entity after a single-row INSERT:

```python
new_id = executor.write("INSERT INTO notes (title) VALUES (:title)", {"title": "Hello"})
return Note(id=new_id, title="Hello")
```

Use `rowcount` to detect a missing row on UPDATE / DELETE:

```python
affected = executor.write("UPDATE notes SET title=:title WHERE id=:id", {"title": t, "id": pk})
if affected == 0:
raise NoteNotFoundException(pk)
```

### `SqlAlchemyTransactionManager`

Manages transactions. Prefer `transactional()` over manual `begin/commit/rollback`.
Expand Down
13 changes: 13 additions & 0 deletions src/nene2/database/sqlalchemy_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ def fetch_one(self, sql: str, params: dict[str, Any] | None = None) -> dict[str,
raise DatabaseConnectionException(str(exc)) from exc

def write(self, sql: str, params: dict[str, Any] | None = None) -> int:
"""Execute INSERT / UPDATE / DELETE and return a meaningful int.

Return value semantics:
- INSERT with AUTOINCREMENT/SERIAL column → ``lastrowid`` (the new row's PK, always > 0)
- INSERT without auto-PK, or multi-row INSERT → falls back to ``rowcount``
- UPDATE / DELETE → ``rowcount`` (number of rows affected; 0 means nothing matched)

Use the return value to detect missing rows::

affected = executor.write("UPDATE ... WHERE id = :id", {"id": pk})
if affected == 0:
raise NotFoundException(pk)
"""
try:
with self._engine.begin() as conn:
result = conn.execute(text(sql), params or {})
Expand Down
Loading