mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-12 00:30:11 +00:00
feat(models): basic rust impl
This commit is contained in:
parent
0862964305
commit
3e194d7c8a
7 changed files with 479 additions and 2 deletions
107
Cargo.lock
generated
107
Cargo.lock
generated
|
|
@ -444,6 +444,7 @@ dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"serde",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
@ -623,6 +624,40 @@ dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.66",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.66",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dashmap"
|
name = "dashmap"
|
||||||
version = "5.4.0"
|
version = "5.4.0"
|
||||||
|
|
@ -890,9 +925,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fred"
|
name = "fred"
|
||||||
version = "9.3.0"
|
version = "9.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ac76d6e24da83723c1d118a1d3b794d883eec94715eeaa611698558d5547048"
|
checksum = "3cdd5378252ea124b712e0ac55147d26ae3af575883b34b8423091a4c719606b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|
@ -1493,6 +1528,12 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
@ -1539,6 +1580,17 @@ dependencies = [
|
||||||
"hashbrown 0.14.5",
|
"hashbrown 0.14.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inherent"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.66",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.7.1"
|
version = "2.7.1"
|
||||||
|
|
@ -1860,6 +1912,15 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "model_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.66",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nibble_vec"
|
name = "nibble_vec"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -2188,6 +2249,19 @@ version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pluralkit_models"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"model_macros",
|
||||||
|
"sea-query",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sqlx",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
version = "0.17.14"
|
version = "0.17.14"
|
||||||
|
|
@ -2860,6 +2934,30 @@ dependencies = [
|
||||||
"untrusted 0.9.0",
|
"untrusted 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sea-query"
|
||||||
|
version = "0.32.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "085e94f7d7271c0393ac2d164a39994b1dff1b06bc40cd9a0da04f3d672b0fee"
|
||||||
|
dependencies = [
|
||||||
|
"inherent",
|
||||||
|
"sea-query-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sea-query-derive"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"heck 0.4.1",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.66",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.11.0"
|
version = "2.11.0"
|
||||||
|
|
@ -3034,6 +3132,7 @@ version = "1.0.117"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -3285,6 +3384,7 @@ dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
"either",
|
"either",
|
||||||
|
|
@ -3367,6 +3467,7 @@ dependencies = [
|
||||||
"bitflags 2.5.0",
|
"bitflags 2.5.0",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
"digest",
|
"digest",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
|
|
@ -3410,6 +3511,7 @@ dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bitflags 2.5.0",
|
"bitflags 2.5.0",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"etcetera",
|
"etcetera",
|
||||||
|
|
@ -3447,6 +3549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680"
|
checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
|
"chrono",
|
||||||
"flume",
|
"flume",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ members = [
|
||||||
"./services/gateway",
|
"./services/gateway",
|
||||||
"./services/avatars",
|
"./services/avatars",
|
||||||
"./services/scheduled_tasks",
|
"./services/scheduled_tasks",
|
||||||
|
|
||||||
|
"./lib/models",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
|
||||||
13
lib/model_macros/Cargo.toml
Normal file
13
lib/model_macros/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "model_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "1.0"
|
||||||
|
proc-macro2 = "1.0"
|
||||||
|
syn = "2.0"
|
||||||
|
|
||||||
241
lib/model_macros/src/lib.rs
Normal file
241
lib/model_macros/src/lib.rs
Normal file
|
|
@ -0,0 +1,241 @@
|
||||||
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{parse_macro_input, DeriveInput, Expr, Ident, Meta, Type};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum ElemPatchability {
|
||||||
|
None,
|
||||||
|
Private,
|
||||||
|
Public,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct ModelField {
|
||||||
|
name: Ident,
|
||||||
|
ty: Type,
|
||||||
|
patch: ElemPatchability,
|
||||||
|
json: Option<Expr>,
|
||||||
|
is_privacy: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_field(field: syn::Field) -> ModelField {
|
||||||
|
let mut f = ModelField {
|
||||||
|
name: field.ident.expect("field missing ident"),
|
||||||
|
ty: field.ty,
|
||||||
|
patch: ElemPatchability::None,
|
||||||
|
json: None,
|
||||||
|
is_privacy: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
for attr in field.attrs.iter() {
|
||||||
|
match &attr.meta {
|
||||||
|
Meta::Path(path) => {
|
||||||
|
let ident = path.segments[0].ident.to_string();
|
||||||
|
match ident.as_str() {
|
||||||
|
"private_patchable" => match f.patch {
|
||||||
|
ElemPatchability::None => {
|
||||||
|
f.patch = ElemPatchability::Private;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("cannot have multiple patch tags on same field");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patchable" => match f.patch {
|
||||||
|
ElemPatchability::None => {
|
||||||
|
f.patch = ElemPatchability::Public;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("cannot have multiple patch tags on same field");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"privacy" => f.is_privacy = true,
|
||||||
|
_ => panic!("unknown attribute"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Meta::NameValue(nv) => match nv.path.segments[0].ident.to_string().as_str() {
|
||||||
|
"json" => {
|
||||||
|
if f.json.is_some() {
|
||||||
|
panic!("cannot set json multiple times for same field");
|
||||||
|
}
|
||||||
|
f.json = Some(nv.value.clone());
|
||||||
|
}
|
||||||
|
_ => panic!("unknown attribute"),
|
||||||
|
},
|
||||||
|
Meta::List(_) => panic!("unknown attribute"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(f.patch, ElemPatchability::Public) && f.json.is_none() {
|
||||||
|
panic!("must have json name to be publicly patchable");
|
||||||
|
}
|
||||||
|
|
||||||
|
f
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn pk_model(
|
||||||
|
_args: proc_macro::TokenStream,
|
||||||
|
input: proc_macro::TokenStream,
|
||||||
|
) -> proc_macro::TokenStream {
|
||||||
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
|
let model_type = match ast.data {
|
||||||
|
syn::Data::Struct(struct_data) => struct_data,
|
||||||
|
_ => panic!("pk_model can only be used on a struct"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let tname = Ident::new(&format!("PK{}", ast.ident), Span::call_site());
|
||||||
|
let patchable_name = Ident::new(&format!("PK{}Patch", ast.ident), Span::call_site());
|
||||||
|
|
||||||
|
let fields = if let syn::Fields::Named(fields) = model_type.fields {
|
||||||
|
fields
|
||||||
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|f| parse_field(f.clone()))
|
||||||
|
.collect::<Vec<ModelField>>()
|
||||||
|
} else {
|
||||||
|
panic!("fields of a struct must be named");
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{}: {:#?}", tname, fields);
|
||||||
|
|
||||||
|
let tfields = mk_tfields(fields.clone());
|
||||||
|
let from_json = mk_tfrom_json(fields.clone());
|
||||||
|
let from_sql = mk_tfrom_sql(fields.clone());
|
||||||
|
let to_json = mk_tto_json(fields.clone());
|
||||||
|
|
||||||
|
let fields: Vec<ModelField> = fields
|
||||||
|
.iter()
|
||||||
|
.filter(|f| !matches!(f.patch, ElemPatchability::None))
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let patch_fields = mk_patch_fields(fields.clone());
|
||||||
|
let patch_from_json = mk_patch_from_json(fields.clone());
|
||||||
|
let patch_validate = mk_patch_validate(fields.clone());
|
||||||
|
let patch_to_json = mk_patch_to_json(fields.clone());
|
||||||
|
let patch_to_sql = mk_patch_to_sql(fields.clone());
|
||||||
|
|
||||||
|
return quote! {
|
||||||
|
#[derive(sqlx::FromRow, Debug, Clone)]
|
||||||
|
pub struct #tname {
|
||||||
|
#tfields
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #tname {
|
||||||
|
pub fn from_json(input: String) -> Self {
|
||||||
|
#from_json
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_json(self) -> String {
|
||||||
|
#to_json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct #patchable_name {
|
||||||
|
#patch_fields
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #patchable_name {
|
||||||
|
pub fn from_json(input: String) -> Self {
|
||||||
|
#patch_from_json
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate(self) -> bool {
|
||||||
|
#patch_validate
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_sql(self) -> sea_query::UpdateStatement {
|
||||||
|
// sea_query::Query::update()
|
||||||
|
#patch_to_sql
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_json(self) -> String {
|
||||||
|
#patch_to_json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mk_tfields(fields: Vec<ModelField>) -> TokenStream {
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let name = f.name.clone();
|
||||||
|
let ty = f.ty.clone();
|
||||||
|
quote! {
|
||||||
|
#name: #ty,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
fn mk_tfrom_json(fields: Vec<ModelField>) -> TokenStream {
|
||||||
|
quote! { unimplemented!(); }
|
||||||
|
}
|
||||||
|
fn mk_tfrom_sql(fields: Vec<ModelField>) -> TokenStream {
|
||||||
|
quote! { unimplemented!(); }
|
||||||
|
}
|
||||||
|
fn mk_tto_json(fields: Vec<ModelField>) -> TokenStream {
|
||||||
|
// todo: check privacy access
|
||||||
|
let fielddefs: TokenStream = fields
|
||||||
|
.iter()
|
||||||
|
.filter_map(|f| {
|
||||||
|
f.json.as_ref().map(|v| {
|
||||||
|
let tname = f.name.clone();
|
||||||
|
quote! {
|
||||||
|
#v: self.#tname,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let privacyfielddefs: TokenStream = fields
|
||||||
|
.iter()
|
||||||
|
.filter_map(|f| {
|
||||||
|
if f.is_privacy {
|
||||||
|
let tname = f.name.clone();
|
||||||
|
let tnamestr = f.name.clone().to_string();
|
||||||
|
Some(quote! {
|
||||||
|
#tnamestr: self.#tname,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
serde_json::to_string(&serde_json::json!({
|
||||||
|
#fielddefs
|
||||||
|
"privacy": {
|
||||||
|
#privacyfielddefs
|
||||||
|
}
|
||||||
|
})).expect("json serializing generated models should not fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mk_patch_fields(fields: Vec<ModelField>) -> TokenStream {
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let name = f.name.clone();
|
||||||
|
let ty = f.ty.clone();
|
||||||
|
quote! {
|
||||||
|
#name: Option<#ty>,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
fn mk_patch_validate(_fields: Vec<ModelField>) -> TokenStream {
|
||||||
|
quote! { true }
|
||||||
|
}
|
||||||
|
fn mk_patch_from_json(fields: Vec<ModelField>) -> TokenStream {
|
||||||
|
quote! { unimplemented!(); }
|
||||||
|
}
|
||||||
|
fn mk_patch_to_sql(fields: Vec<ModelField>) -> TokenStream {
|
||||||
|
quote! { unimplemented!(); }
|
||||||
|
}
|
||||||
|
fn mk_patch_to_json(fields: Vec<ModelField>) -> TokenStream {
|
||||||
|
quote! { unimplemented!(); }
|
||||||
|
}
|
||||||
13
lib/models/Cargo.toml
Normal file
13
lib/models/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "pluralkit_models"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
chrono = { workspace = true, features = ["serde"] }
|
||||||
|
model_macros = { path = "../model_macros" }
|
||||||
|
sea-query = "0.32.1"
|
||||||
|
serde = { workspace = true }
|
||||||
|
serde_json = { workspace = true, features = ["preserve_order"] }
|
||||||
|
sqlx = { workspace = true, default-features = false, features = ["chrono"] }
|
||||||
|
uuid = { workspace = true }
|
||||||
2
lib/models/src/lib.rs
Normal file
2
lib/models/src/lib.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
mod system;
|
||||||
|
pub use system::*;
|
||||||
103
lib/models/src/system.rs
Normal file
103
lib/models/src/system.rs
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use model_macros::pk_model;
|
||||||
|
|
||||||
|
use chrono::NaiveDateTime;
|
||||||
|
use sqlx::{postgres::PgTypeInfo, Database, Decode, Postgres, Type};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
// todo: fix this
|
||||||
|
pub type SystemId = i32;
|
||||||
|
|
||||||
|
// // todo: move this
|
||||||
|
#[derive(serde::Serialize, Debug, Clone)]
|
||||||
|
pub enum PrivacyLevel {
|
||||||
|
#[serde(rename = "public")]
|
||||||
|
Public = 1,
|
||||||
|
#[serde(rename = "private")]
|
||||||
|
Private = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type<Postgres> for PrivacyLevel {
|
||||||
|
fn type_info() -> PgTypeInfo {
|
||||||
|
PgTypeInfo::with_name("INT4")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PrivacyLevel> for i32 {
|
||||||
|
fn from(enum_value: PrivacyLevel) -> Self {
|
||||||
|
enum_value as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for PrivacyLevel {
|
||||||
|
fn from(value: i32) -> Self {
|
||||||
|
match value {
|
||||||
|
1 => PrivacyLevel::Public,
|
||||||
|
2 => PrivacyLevel::Private,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyType;
|
||||||
|
|
||||||
|
impl<'r, DB: Database> Decode<'r, DB> for PrivacyLevel
|
||||||
|
where
|
||||||
|
i32: Decode<'r, DB>,
|
||||||
|
{
|
||||||
|
fn decode(
|
||||||
|
value: <DB as Database>::ValueRef<'r>,
|
||||||
|
) -> Result<Self, Box<dyn Error + 'static + Send + Sync>> {
|
||||||
|
let value = <i32 as Decode<DB>>::decode(value)?;
|
||||||
|
Ok(Self::from(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pk_model]
|
||||||
|
struct System {
|
||||||
|
id: SystemId,
|
||||||
|
#[json = "id"]
|
||||||
|
#[private_patchable]
|
||||||
|
hid: String,
|
||||||
|
#[json = "uuid"]
|
||||||
|
uuid: Uuid,
|
||||||
|
#[json = "name"]
|
||||||
|
name: Option<String>,
|
||||||
|
#[json = "description"]
|
||||||
|
description: Option<String>,
|
||||||
|
#[json = "tag"]
|
||||||
|
tag: Option<String>,
|
||||||
|
#[json = "pronouns"]
|
||||||
|
pronouns: Option<String>,
|
||||||
|
#[json = "avatar_url"]
|
||||||
|
avatar_url: Option<String>,
|
||||||
|
#[json = "banner_image"]
|
||||||
|
banner_image: Option<String>,
|
||||||
|
#[json = "color"]
|
||||||
|
color: Option<String>,
|
||||||
|
token: Option<String>,
|
||||||
|
#[json = "webhook_url"]
|
||||||
|
webhook_url: Option<String>,
|
||||||
|
webhook_token: Option<String>,
|
||||||
|
#[json = "created"]
|
||||||
|
created: NaiveDateTime,
|
||||||
|
#[privacy]
|
||||||
|
name_privacy: PrivacyLevel,
|
||||||
|
#[privacy]
|
||||||
|
avatar_privacy: PrivacyLevel,
|
||||||
|
#[privacy]
|
||||||
|
description_privacy: PrivacyLevel,
|
||||||
|
#[privacy]
|
||||||
|
banner_privacy: PrivacyLevel,
|
||||||
|
#[privacy]
|
||||||
|
member_list_privacy: PrivacyLevel,
|
||||||
|
#[privacy]
|
||||||
|
front_privacy: PrivacyLevel,
|
||||||
|
#[privacy]
|
||||||
|
front_history_privacy: PrivacyLevel,
|
||||||
|
#[privacy]
|
||||||
|
group_list_privacy: PrivacyLevel,
|
||||||
|
#[privacy]
|
||||||
|
pronoun_privacy: PrivacyLevel,
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue