I'd like to store all of that together in one struct to have some sort of type I can pass around.
This is obviously not supported by Rust. What's the best solution in such case?
I looked at ouroboros, but it seems this is not a usecase it supports.
I'm not sure what you mean by "but not directly", but this is in fact what is generally meant by "self-referencial struct" (Statement<'conn> contains a &'conn Connection and Rows<'stmt>/Row<'stmt> contain a &'stmt Statement<'stmt>).
So it is the usecase ouroboros and yoke and the like are aimed at, but I'm afraid I won't be of help when it comes to actually getting things to compile with those crates.
No matter how appealing "storing all of these together" might be, you really don't want to do it. Prepared statements and results from executing a query are temporary intermediate types. You almost always want to extract owned values from the query result and store those instead.
There is a very important warning in the docs which should be noted: Row in duckdb - Rust
This ValueRef is valid only as long as this Row, which is enforced by it’s lifetime. This means that while this method is completely safe, it can be somewhat difficult to use, and most callers will be better served by get or get_unwrap.
(Emphasis my own.)
And ... yeah, that looks familiar, where have I seen this before? Oh yeah, it's the same phrasing used in Row in rusqlite - Rust!
It is of course quite nice that you are allowed to access values in your in-memory database through just a simple pointer indirection, but actually doing so in practice is rare if you want readable code (e.g. not a 5,000 line function with all of your business logic inlined). You probably don't need to do that anyway. Go ahead and clone the data into your structs, it will be ok.
I do. I just don't want to do that in the function that creates connection.
So I could consider this to be a control flow issue rather then memory management, but still, even for the sake of learning, I'd like to know how to do it (safely).
using ouroboros, self_cell or yoke. All of them do require using two structs however since there are two different parents/owners (statement borrows from connection while rows borrows from statement).
Cargo.toml:
[dependencies]
ouroboros = "0.18.4"
self_cell = "1.1.0"
yoke = { version = "=0.7.4", features = ["derive"] }