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
18 changes: 14 additions & 4 deletions content/v4/rdbms-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,21 +149,31 @@ addEventListener('fetch', async (event: FetchEvent) => {
The code below shows use of the [Postgres](https://spinframework.github.io/spin-python-sdk/v4/postgres.html) module and its [open](https://spinframework.github.io/spin-python-sdk/v4/postgres.html#spin_sdk.postgres.open) function for opening a connection to the database:

```python
from spin_sdk import http, postgres
from spin_sdk import http, util
from spin_sdk.http import Request, Response
from spin_sdk.postgres import Connection

class HttpHandler(http.Handler):
async def handle_request(self, request: Request) -> Response:
with await postgres.open("user=postgres dbname=spin_dev host=localhost sslmode=disable password=password") as db:
print(db.query("SELECT * FROM test", []))
with await Connection.open("user=postgres dbname=spin_dev host=localhost sslmode=disable password=password") as db:
columns, stream, future = await db.query("SELECT * FROM test", [])
rows = await util.collect((stream, future))

return Response(
200,
{"content-type": "text/plain"},
bytes("Hello from Python!", "utf-8")
bytes(str(rows), "utf-8")
)
```

**General Notes**
* The `query` method returns a Tuple containing a list of `columns`, a list of `rows` encapsulated via a [StreamReader](https://github.com/bytecodealliance/componentize-py/blob/1b3d2e936868307a48fb70941dcad71b54e844f8/bundled/componentize_py_async_support/streams.py#L101), and a [FutureReader](https://github.com/bytecodealliance/componentize-py/blob/1b3d2e936868307a48fb70941dcad71b54e844f8/bundled/componentize_py_async_support/futures.py#L11). You _must_ check when the stream ends, to determine if the stream ended normally, or was terminated prematurely due to an error.

> As seen in the example above, you can utilize the [collect](https://spinframework.github.io/spin-python-sdk/v4/util.html#spin_sdk.util.collect) method from the `util` package to handle the `StreamReader` and `FutureReader` pair, aggregating the resulting rows into memory.

* The `Connection` object doesn't surface the `close` function.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Components can't deterministically close a connection? (Oh is this to get around "what if they close it while the row stream is still being traversed" kind of thing?)

Copy link
Copy Markdown
Contributor Author

@vdice vdice Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, not quite sure of the genesis of this entry (predates the updated v4 docs) Ah, I see I swiped this from the pre-existing note in the sqlite guide. Remove/update both?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's true, then keep. If it's untrue, then remove. (My guess is copypasta from the Rust Connection object around the time we switched from "pass the address" to "methods on a resource".)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to say it is true insofar as neither the SDK nor the underlying WITs surface a close function. As to why they don't, I'm not sure on the details.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, perhaps because the connection resource doesn't, and you instead use resource drop functionality? Not a worry for now, let's review after 4.0 and figure out 1. if Spin is doing this correctly and 2. how to surface it in SDKs. Sorry for the noise.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created #195 to track.

* Errors are surfaced as exceptions.

You can find a complete outbound PostgreSQL example in the [Spin Python SDK repository on GitHub](https://github.com/spinframework/spin-python-sdk/tree/main/examples/spin-postgres). There is also an [Outbound MySQL example](https://github.com/spinframework/spin-python-sdk/tree/main/examples/spin-mysql) available.

{{ blockEnd }}
Expand Down
20 changes: 12 additions & 8 deletions content/v4/sqlite-api-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,20 @@ addEventListener('fetch', async (event: FetchEvent) => {

> [**Want to go straight to the reference documentation?** Find it here.](https://spinframework.github.io/spin-python-sdk/v4/sqlite.html)

To use SQLite functions, use the `sqlite` module in the Python SDK. The [`open`](https://spinframework.github.io/spin-python-sdk/v4/sqlite.html#spin_sdk.sqlite.open) and [`open_default`](https://spinframework.github.io/spin-python-sdk/v4/sqlite.html#spin_sdk.sqlite.open_default) functions return a [`Connection` object](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_sqlite_sqlite_3_1_0.html#spin_sdk.wit.imports.spin_sqlite_sqlite_3_1_0.Connection). The `Connection` object provides the [`execute` method](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_sqlite_sqlite_3_1_0.html#spin_sdk.wit.imports.spin_sqlite_sqlite_3_1_0.Connection.execute) as described above. For example:
To use SQLite functions, use the `sqlite` module in the Python SDK. The [`open`](https://spinframework.github.io/spin-python-sdk/v4/sqlite.html#spin_sdk.sqlite.open) and [`open_default`](https://spinframework.github.io/spin-python-sdk/v4/sqlite.html#spin_sdk.sqlite.open_default) functions return a [`Connection` object](https://spinframework.github.io/spin-python-sdk/v4/sqlite.html#spin_sdk.sqlite.Connection). The `Connection` object provides the [`execute` method](https://spinframework.github.io/spin-python-sdk/v4/sqlite.html#spin_sdk.sqlite.Connection.execute) as described above. For example:

```python
from spin_sdk import http, sqlite
from spin_sdk import http, util
from spin_sdk.http import Request, Response
from spin_sdk.sqlite import Value_Integer
from spin_sdk.sqlite import Connection, Value_Text, Value_Integer

class HttpHandler(http.Handler):
async def handle_request(self, request: Request) -> Response:
with await sqlite.open_default() as db:
result = db.execute("SELECT * FROM todos WHERE id > (?);", [Value_Integer(1)])
rows = result.rows

with await Connection.open_default() as db:
await db.execute("INSERT INTO todos (description, due) VALUES (?, ?)", [Value_Text("Try out Spin SQLite"), Value_Text("Friday")])
columns, stream, future = await db.execute("SELECT * FROM todos WHERE id > (?);", [Value_Integer(1)])
rows = await util.collect((stream, future))

return Response(
200,
{"content-type": "text/plain"},
Expand All @@ -179,7 +180,10 @@ class HttpHandler(http.Handler):
```

**General Notes**
* The `execute` method returns [a `QueryResult` object](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_sqlite_sqlite_3_1_0.html#spin_sdk.wit.imports.spin_sqlite_sqlite_3_1_0.QueryResult) with `rows` and `columns` methods. `columns` returns a list of strings representing column names. `rows` is an array of rows, each of which is an array of [`RowResult`](https://spinframework.github.io/spin-python-sdk/v4/wit/imports/spin_sqlite_sqlite_3_1_0.html#spin_sdk.wit.imports.spin_sqlite_sqlite_3_1_0.RowResult) in the same order as `columns`.
* The `execute` method returns a Tuple containing a list of `columns`, a list of `rows` encapsulated via a [StreamReader](https://github.com/bytecodealliance/componentize-py/blob/1b3d2e936868307a48fb70941dcad71b54e844f8/bundled/componentize_py_async_support/streams.py#L101), and a [FutureReader](https://github.com/bytecodealliance/componentize-py/blob/1b3d2e936868307a48fb70941dcad71b54e844f8/bundled/componentize_py_async_support/futures.py#L11). You _must_ check when the stream ends, to determine if the stream ended normally, or was terminated prematurely due to an error.

> As seen in the example above, you can utilize the [collect](https://spinframework.github.io/spin-python-sdk/v4/util.html#spin_sdk.util.collect) method from the `util` package to handle the `StreamReader` and `FutureReader` pair, aggregating the resulting rows into memory.

* The `Connection` object doesn't surface the `close` function.
* Errors are surfaced as exceptions.

Expand Down
Loading