use std::collections::HashMap; use once_cell::sync::OnceCell; use sqlx::{ error::BoxDynError, postgres::{types::Oid, PgHasArrayType, PgTypeInfo}, query_as, types::Json, Decode, Encode, Executor, FromRow, Postgres, Type, }; use crate::index::DependencyKind; #[derive(Clone, Copy, Default, Debug)] #[repr(transparent)] pub struct PgU32(pub u32); impl PgU32 { fn to_i32(self) -> i32 { i32::from_ne_bytes(self.0.to_ne_bytes()) } fn from_i32(v: i32) -> Self { Self(u32::from_ne_bytes(v.to_ne_bytes())) } } impl<'r> Decode<'r, Postgres> for PgU32 { fn decode( value: >::ValueRef, ) -> Result { i32::decode(value).map(Self::from_i32) } } impl<'q> Encode<'q, Postgres> for PgU32 { fn encode_by_ref( &self, buf: &mut >::ArgumentBuffer, ) -> sqlx::encode::IsNull { self.to_i32().encode(buf) } fn produces(&self) -> Option<::TypeInfo> { self.to_i32().produces() } fn size_hint(&self) -> usize { self.to_i32().size_hint() } } impl Type for PgU32 { fn type_info() -> ::TypeInfo { i32::type_info() } } impl PgHasArrayType for PgU32 { fn array_type_info() -> PgTypeInfo { i32::array_type_info() } } #[derive(FromRow)] pub struct DbUser { pub id: PgU32, pub login: String, pub credential: String, pub name: Option, } #[derive(FromRow)] pub struct DbCrate { pub id: PgU32, pub name: String, pub publisher: PgU32, pub owners: Vec, } #[derive(FromRow)] pub struct DbVersion { pub id: PgU32, pub vers: String, pub cksum: String, pub yanked: bool, pub links: Option, pub crate_id: PgU32, pub features: Vec, pub authors: Vec, pub description: Option, pub documentation: Option, pub homepage: Option, pub readme: Option, pub readme_file: Option, pub keywords: Vec, pub categories: Vec, pub license: Option, pub license_file: Option, pub repository: Option, pub badges: Json>>, } #[derive(FromRow)] pub struct DbDep { pub id: PgU32, pub name: String, pub version_req: String, pub optional: bool, pub default_features: bool, pub target: Option, pub kind: DependencyKind, pub registry: Option, pub package: Option, pub features: Vec, pub version_id: PgU32, } #[derive(Type)] #[sqlx(type_name = "version_feature")] pub struct DbVersionFeature { pub feature: String, pub enables: Vec, } static VERSION_FEATURE_ARRAY_OID: OnceCell = OnceCell::new(); pub async fn init<'c, E: Executor<'c, Database = Postgres> + Copy>( e: E, ) -> Result<(), BoxDynError> { // explicitly ignore the result, since it currently throws an error if the type already exists let _ = e.execute(include_str!("create.sql")).await; let (oid,): (Oid,) = query_as("SELECT typarray FROM pg_type WHERE typname = 'version_feature'") .fetch_one(e) .await?; VERSION_FEATURE_ARRAY_OID .set(oid) .expect("db::init called multiple times"); Ok(()) } impl PgHasArrayType for DbVersionFeature { fn array_type_info() -> PgTypeInfo { PgTypeInfo::with_oid(*VERSION_FEATURE_ARRAY_OID.get().unwrap()) } }