The following are ideas and not final.
Tuple Struct (of 1)
#[derive(sqlx::Type)]
// transparent indicates that this type is purely for
// documentation and it should act exactly as if it were the wrapped type in all aspects
#[sqlx(transparent)]
struct MyType(i32);
Enum
#[derive(sqlx::Type)]
// specify the OID explicitly for the type (optionally the OID for when its used as an array)
#[sqlx(postgres(oid = 1212, array_oid = 21341))]
// by default we encode and decode as a string and rely on first-class support
// for enumerations in the database server
#[sqlx(repr(i32))]
// by default we should snake_case the type name and look up its OID
// you should be able to use a container-level attribute to rename the type name
#[sqlx(rename = "myenum")]
enum MyEnum {
TheFoo,
// By default we should snake_case rename but also allow renames
#[sqlx(rename = "foothe")]
FooThe
}
Struct
// In Postgres you can define your own composites or structs
// We should be able to support this
#[derive(sqlx::Type)]
struct Foo { a: i32 }
// Additionally, perhaps something like the following for strongly typed JSON
// from Postgres or MySQL
#[derive(sqlx::Type)]
#[sqlx(repr(json))]
struct Bar { b: i64 }
Basic idea of implementation is these derives would implement HasSqlType and add the Encode and Decode derives. Can proc derives be recursive (e.g., can this derive generate more derive macro invocations)?
This will be an excellent addition to the library, for sure!
Can proc derives be recursive (e.g., can this derive generate more derive macro invocations)?
No because they cannot emit more #[derive] attributes for the same item (their output is purely additive). However, we can simply call into the derive implementations for Encode and Decode and merge the token streams instead.
tuple structs of one and enums seem pretty straight forward. how does encode & decode work for structs though? and how would repr(json) do? add derives for serde and use serde_json?
#[derive(sqlx::Type)]
#[repr(transparent)]
struct Health(i32);
INT
#[derive(sqlx::Type)]
#[sqlx(postgres(oid = 101010))]
enum Direction { Up, Down, Left, Right };
CREATE TYPE direction AS ENUM ('up', 'down', 'left', 'right');
ENUM('up', 'down', 'left', 'right')
#[derive(sqlx::Type)]
#[repr(i32)]
enum Direction { Up, Down, Left, Right };
INT
#[derive(sqlx::Type)]
#[sqlx(postgres(oid = 101010))]
struct Point { x: i16, y: i16 };
CREATE TYPE point AS (
x INT2,
y INT2
);
repr(i32) or sqlx(repr(i32)) for Weak Enums ?@Freax13 Let me know if you have any other questions.
Encode and Decode for structs in Postgres is a touch complicated. The only documentation is in the source code. It's a specific binary encoding. If you don't feel comfortable tackling this, that's totally fine.
Here is the best "docs" I can find on it.
https://github.com/scrive/hpqtypes/blob/master/libpqtypes/src/record.c
turns out deriving HasSqlType for transparent types (and weak enums?) isnt as straight forward as I thought it would be. ideally we would want something like
struct Foo(i32);
impl<DB: sqlx::Database> sqlx::types::HasSqlType<Foo> for DB where DB: sqlx::types::HasSqlType<i32> {
fn type_info() -> Self::TypeInfo {
<Self as HasSqlType<i32>>::type_info()
}
}
however this doesnt work due to the orphan rules (the two foreign traits being HasSqlType and Database)
so we could either
#[derive(HasSqlType(MySql,Postgres,OtherDB))]
struct Foo(i32);
I like option 1. here. Users would already need to write the derive for their code, and an additional param for HasSqlType specifying the DB type being used seems pretty logical, especially given that doing so will reduce the amount of code which would need to be generated.
however this doesnt work due to the orphan rules (the two foreign traits being HasSqlType and Database)
This is actually changing in 1.41 to be allowed. Orphan rules are relaxed if the type parameter of a foreign trait is your crate-local type.
See: https://github.com/rust-lang/rust/blob/master/RELEASES.md#language
Until 1.41 is out and we depend on it, I would recommend exposing a boolean or something from sqlx as #[doc(hidden)] that we can look at and produce implementations.
some rules will be relaxed, but it still wont work
playground example
Right.. It's the for T part that still won't be allowed.
Regardless, thinking about this again, the derive should probably just follow the feature flags that are being applied to the sqlx-macros crate.
If the postgres feature is present, emit an explicit for Postgres impl.
Most helpful comment
Right.. It's the
for Tpart that still won't be allowed.Regardless, thinking about this again, the derive should probably just follow the feature flags that are being applied to the
sqlx-macroscrate.If the
postgresfeature is present, emit an explicitfor Postgresimpl.