Stronger linter on sync generator

This commit is contained in:
Ericson Soares 2024-06-20 17:03:39 -03:00
parent 6cdaed47ec
commit aa9a117a22
7 changed files with 393 additions and 321 deletions

View file

@ -28,6 +28,7 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
pub p2p_discovery: Option<P2PDiscoveryState>,
pub p2p_remote_access: Option<bool>,
pub p2p_manual_peers: Option<HashSet<String>>,
#[cfg(feature = "ai")]
pub image_labeler_version: Option<String>,
}
R.mutation(|node, args: ChangeNodeNameArgs| async move {

View file

@ -10,17 +10,19 @@ pub enum AttributeFieldValue<'a> {
#[allow(unused)]
impl AttributeFieldValue<'_> {
pub fn as_single(&self) -> Option<&str> {
match self {
AttributeFieldValue::Single(field) => Some(field),
_ => None,
pub const fn as_single(&self) -> Option<&str> {
if let AttributeFieldValue::Single(field) = self {
Some(field)
} else {
None
}
}
pub fn as_list(&self) -> Option<&Vec<&str>> {
match self {
AttributeFieldValue::List(fields) => Some(fields),
_ => None,
pub const fn as_list(&self) -> Option<&Vec<&str>> {
if let AttributeFieldValue::List(fields) = self {
Some(fields)
} else {
None
}
}
}
@ -36,12 +38,14 @@ impl<'a> Attribute<'a> {
parser::parse(input).map(|(_, a)| a).map_err(|_| ())
}
pub fn field(&self, name: &str) -> Option<&AttributeFieldValue> {
self.fields.iter().find(|(n, _)| *n == name).map(|(_, v)| v)
pub fn field(&self, name: &str) -> Option<&AttributeFieldValue<'_>> {
self.fields
.iter()
.find_map(|(n, v)| (*n == name).then_some(v))
}
}
pub fn model_attributes(model: ModelWalker) -> Vec<Attribute> {
pub fn model_attributes(model: ModelWalker<'_>) -> Vec<Attribute<'_>> {
model
.ast_model()
.documentation()

View file

@ -1,11 +1,11 @@
use nom::{
branch::alt,
bytes::complete::*,
character::complete::*,
combinator::*,
bytes::complete::{is_not, tag},
character::complete::{alpha1, char, multispace0},
combinator::{map, opt},
error::{ErrorKind, ParseError},
multi::*,
sequence::*,
multi::separated_list1,
sequence::{delimited, separated_pair},
AsChar, IResult, InputTakeAtPosition,
};
@ -24,7 +24,7 @@ fn parens(input: &str) -> IResult<&str, &str> {
delimited(char('('), is_not(")"), char(')'))(input)
}
fn single_value<T, E: ParseError<T>>(i: T) -> IResult<T, T, E>
fn single_value<T, E: ParseError<T>>(i: &T) -> IResult<T, T, E>
where
T: InputTakeAtPosition,
<T as InputTakeAtPosition>::Item: AsChar,
@ -41,19 +41,19 @@ where
fn list_value(input: &str) -> IResult<&str, Vec<&str>> {
delimited(
char('['),
separated_list1(char(','), remove_ws(single_value)),
separated_list1(char(','), remove_ws(|a| single_value(&a))),
char(']'),
)(input)
}
fn attribute_field_value(input: &str) -> IResult<&str, AttributeFieldValue> {
fn attribute_field_value(input: &str) -> IResult<&str, AttributeFieldValue<'_>> {
remove_ws(alt((
map(list_value, AttributeFieldValue::List),
map(single_value, AttributeFieldValue::Single),
map(|a| list_value(a), AttributeFieldValue::List),
map(|a| single_value(&a), AttributeFieldValue::Single),
)))(input)
}
fn attribute_field(input: &str) -> IResult<&str, (&str, AttributeFieldValue)> {
fn attribute_field(input: &str) -> IResult<&str, (&str, AttributeFieldValue<'_>)> {
remove_ws(separated_pair(
remove_ws(is_not(":")),
char(':'),
@ -61,11 +61,11 @@ fn attribute_field(input: &str) -> IResult<&str, (&str, AttributeFieldValue)> {
))(input)
}
fn attribute_fields(input: &str) -> IResult<&str, Vec<(&str, AttributeFieldValue)>> {
fn attribute_fields(input: &str) -> IResult<&str, Vec<(&str, AttributeFieldValue<'_>)>> {
separated_list1(char(','), attribute_field)(input)
}
pub fn parse(input: &str) -> IResult<&str, Attribute> {
pub fn parse(input: &str) -> IResult<&str, Attribute<'_>> {
let (input, _) = remove_ws(tag("@"))(input)?;
let (input, name) = alpha1(input)?;
let (input, values_str) = opt(remove_ws(parens))(input)?;
@ -86,7 +86,7 @@ mod test {
fn marker() {
let s = "@local";
let (remaining, attribute) = super::parse(s).unwrap();
let (remaining, attribute) = parse(s).unwrap();
assert_eq!(remaining, "");
assert_eq!(attribute.name, "local");
@ -97,7 +97,7 @@ mod test {
fn single() {
let s = "@local(foo: bar)";
let (remaining, attribute) = super::parse(s).unwrap();
let (remaining, attribute) = parse(s).unwrap();
assert_eq!(remaining, "");
assert_eq!(attribute.name, "local");
@ -113,7 +113,7 @@ mod test {
fn list() {
let s = "@local(foo: [bar, baz])";
let (remaining, attribute) = match super::parse(s) {
let (remaining, attribute) = match parse(s) {
Ok(v) => v,
Err(e) => panic!("{}", e),
};
@ -136,7 +136,7 @@ mod test {
fn multiple() {
let s = "@local(foo: bar, baz: qux)";
let (remaining, attribute) = super::parse(s).unwrap();
let (remaining, attribute) = parse(s).unwrap();
assert_eq!(remaining, "");
assert_eq!(attribute.name, "local");

View file

@ -1,8 +1,31 @@
mod attribute;
mod model;
mod sync_data;
use attribute::*;
#![warn(
clippy::all,
clippy::pedantic,
clippy::correctness,
clippy::perf,
clippy::style,
clippy::suspicious,
clippy::complexity,
clippy::nursery,
clippy::unwrap_used,
unused_qualifications,
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
unused_allocation,
clippy::unnecessary_cast,
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::dbg_macro,
clippy::deprecated_cfg_attr,
clippy::separated_literal_suffix,
deprecated
)]
#![forbid(deprecated_in_future)]
#![allow(clippy::missing_errors_doc, clippy::module_name_repetitions)]
use prisma_client_rust_sdk::{
prelude::*,
@ -11,6 +34,12 @@ use prisma_client_rust_sdk::{
},
};
mod attribute;
mod model;
mod sync_data;
use attribute::{model_attributes, Attribute, AttributeFieldValue};
#[derive(Debug, serde::Serialize, thiserror::Error)]
enum Error {}
@ -38,7 +67,7 @@ pub enum ModelSyncType<'a> {
}
impl<'a> ModelSyncType<'a> {
fn from_attribute(attr: Attribute, model: ModelWalker<'a>) -> Option<Self> {
fn from_attribute(attr: &Attribute<'_>, model: ModelWalker<'a>) -> Option<Self> {
Some(match attr.name {
"local" | "shared" => {
let id = attr
@ -69,14 +98,15 @@ impl<'a> ModelSyncType<'a> {
AttributeFieldValue::List(_) => None,
})
.and_then(|name| {
match model
if let RefinedFieldWalker::Relation(r) = model
.fields()
.find(|f| f.name() == name)
.unwrap_or_else(|| panic!("'{name}' field not found"))
.refine()
{
RefinedFieldWalker::Relation(r) => Some(r),
_ => None,
Some(r)
} else {
None
}
})
.unwrap_or_else(|| panic!("'{name}' must be a relation field"))
@ -96,11 +126,10 @@ impl<'a> ModelSyncType<'a> {
})
}
fn sync_id(&self) -> Vec<FieldWalker> {
fn sync_id(&self) -> Vec<FieldWalker<'_>> {
match self {
// Self::Owned { id } => id.clone(),
Self::Local { id, .. } => vec![*id],
Self::Shared { id, .. } => vec![*id],
Self::Local { id, .. } | Self::Shared { id, .. } => vec![*id],
Self::Relation { group, item, .. } => vec![(*group).into(), (*item).into()],
}
}
@ -127,7 +156,7 @@ impl PrismaGenerator for SDSyncGenerator {
type Error = Error;
fn generate(self, args: GenerateArgs) -> Result<Module, Self::Error> {
fn generate(self, args: GenerateArgs<'_>) -> Result<Module, Self::Error> {
let db = &args.schema.db;
let models_with_sync_types = db
@ -136,13 +165,13 @@ impl PrismaGenerator for SDSyncGenerator {
.map(|(model, attributes)| {
let sync_type = attributes
.into_iter()
.find_map(|a| ModelSyncType::from_attribute(a, model));
.find_map(|a| ModelSyncType::from_attribute(&a, model));
(model, sync_type)
})
.collect::<Vec<_>>();
let model_sync_data = sync_data::r#enum(models_with_sync_types.clone());
let model_sync_data = sync_data::enumerate(&models_with_sync_types);
let mut module = Module::new(
"root",

View file

@ -1,13 +1,14 @@
use prisma_client_rust_sdk::{prelude::*, prisma::prisma_models::walkers::RefinedFieldWalker};
use prisma_models::{ast::ModelId, walkers::Walker};
use crate::{ModelSyncType, ModelWithSyncType};
pub fn module((model, sync_type): ModelWithSyncType) -> Module {
pub fn module((model, sync_type): ModelWithSyncType<'_>) -> Module {
let model_name_snake = snake_ident(model.name());
let sync_id = sync_type.as_ref().map(|sync_type| {
let fields = sync_type.sync_id();
let fields = fields.iter().flat_map(|field| {
let fields = fields.iter().map(|field| {
let name_snake = snake_ident(field.name());
let typ = match field.refine() {
@ -18,58 +19,10 @@ pub fn module((model, sync_type): ModelWithSyncType) -> Module {
}
};
Some(quote!(pub #name_snake: #typ))
quote!(pub #name_snake: #typ)
});
let model_stuff = match sync_type {
ModelSyncType::Relation {
item,
group,
model_id,
} => {
let item_name_snake = snake_ident(item.name());
let item_model_name_snake = snake_ident(item.related_model().name());
let group_name_snake = snake_ident(group.name());
let group_model_name_snake = snake_ident(group.related_model().name());
Some(quote! {
impl sd_sync::RelationSyncId for SyncId {
type ItemSyncId = super::#item_model_name_snake::SyncId;
type GroupSyncId = super::#group_model_name_snake::SyncId;
fn split(&self) -> (&Self::ItemSyncId, &Self::GroupSyncId) {
(
&self.#item_name_snake,
&self.#group_name_snake
)
}
}
pub const MODEL_ID: u16 = #model_id;
impl sd_sync::SyncModel for #model_name_snake::Types {
const MODEL_ID: u16 = MODEL_ID;
}
impl sd_sync::RelationSyncModel for #model_name_snake::Types {
type SyncId = SyncId;
}
})
}
ModelSyncType::Shared { model_id, .. } => Some(quote! {
pub const MODEL_ID: u16 = #model_id;
impl sd_sync::SyncModel for #model_name_snake::Types {
const MODEL_ID: u16 = MODEL_ID;
}
impl sd_sync::SharedSyncModel for #model_name_snake::Types {
type SyncId = SyncId;
}
}),
_ => None,
};
let model_stuff = parse_model(sync_type, &model_name_snake);
quote! {
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
@ -101,8 +54,9 @@ pub fn module((model, sync_type): ModelWithSyncType) -> Module {
let relation_model_name_snake =
snake_ident(relation_field.related_model().name());
match relation_field.referenced_fields() {
Some(i) => {
relation_field.referenced_fields().map_or_else(
|| None,
|i| {
if i.count() == 1 {
Some(quote! {{
let val: std::collections::HashMap<String, rmpv::Value> = ::rmpv::ext::from_value(val).unwrap();
@ -115,17 +69,17 @@ pub fn module((model, sync_type): ModelWithSyncType) -> Module {
} else {
None
}
}
_ => None,
}
},
)
}
}
.map(|body| quote!(#model_name_snake::#field_name_snake::NAME => #body))
});
match field_matches.clone().count() {
0 => quote!(),
_ => quote! {
if field_matches.clone().count() == 0 {
quote!()
} else {
quote! {
impl #model_name_snake::SetParam {
pub fn deserialize(field: &str, val: ::rmpv::Value) -> Option<Self> {
Some(match field {
@ -134,41 +88,11 @@ pub fn module((model, sync_type): ModelWithSyncType) -> Module {
})
}
}
},
}
}
};
let unique_param_impl = {
let field_matches = model
.unique_criterias()
.flat_map(|criteria| match &criteria.fields().next() {
Some(field) if criteria.fields().len() == 1 => {
let field_name_snake = snake_ident(field.name());
Some(quote!(#model_name_snake::#field_name_snake::NAME =>
#model_name_snake::#field_name_snake::equals(
::rmpv::ext::from_value(val).unwrap()
),
))
}
_ => None,
})
.collect::<Vec<_>>();
match field_matches.len() {
0 => quote!(),
_ => quote! {
impl #model_name_snake::UniqueWhereParam {
pub fn deserialize(field: &str, val: ::rmpv::Value) -> Option<Self> {
Some(match field {
#(#field_matches)*
_ => return None
})
}
}
},
}
};
let unique_param_impl = process_unique_params(model, &model_name_snake);
Module::new(
model.name(),
@ -184,3 +108,90 @@ pub fn module((model, sync_type): ModelWithSyncType) -> Module {
},
)
}
#[inline]
fn parse_model(sync_type: &ModelSyncType<'_>, model_name_snake: &Ident) -> Option<TokenStream> {
match sync_type {
ModelSyncType::Relation {
item,
group,
model_id,
} => {
let item_name_snake = snake_ident(item.name());
let item_model_name_snake = snake_ident(item.related_model().name());
let group_name_snake = snake_ident(group.name());
let group_model_name_snake = snake_ident(group.related_model().name());
Some(quote! {
impl sd_sync::RelationSyncId for SyncId {
type ItemSyncId = super::#item_model_name_snake::SyncId;
type GroupSyncId = super::#group_model_name_snake::SyncId;
fn split(&self) -> (&Self::ItemSyncId, &Self::GroupSyncId) {
(
&self.#item_name_snake,
&self.#group_name_snake
)
}
}
pub const MODEL_ID: u16 = #model_id;
impl sd_sync::SyncModel for #model_name_snake::Types {
const MODEL_ID: u16 = MODEL_ID;
}
impl sd_sync::RelationSyncModel for #model_name_snake::Types {
type SyncId = SyncId;
}
})
}
ModelSyncType::Shared { model_id, .. } => Some(quote! {
pub const MODEL_ID: u16 = #model_id;
impl sd_sync::SyncModel for #model_name_snake::Types {
const MODEL_ID: u16 = MODEL_ID;
}
impl sd_sync::SharedSyncModel for #model_name_snake::Types {
type SyncId = SyncId;
}
}),
ModelSyncType::Local { .. } => None,
}
}
#[inline]
fn process_unique_params(model: Walker<'_, ModelId>, model_name_snake: &Ident) -> TokenStream {
let field_matches = model
.unique_criterias()
.filter_map(|criteria| match &criteria.fields().next() {
Some(field) if criteria.fields().len() == 1 => {
let field_name_snake = snake_ident(field.name());
Some(quote!(#model_name_snake::#field_name_snake::NAME =>
#model_name_snake::#field_name_snake::equals(
::rmpv::ext::from_value(val).unwrap()
),
))
}
_ => None,
})
.collect::<Vec<_>>();
if field_matches.is_empty() {
quote!()
} else {
quote! {
impl #model_name_snake::UniqueWhereParam {
pub fn deserialize(field: &str, val: ::rmpv::Value) -> Option<Self> {
Some(match field {
#(#field_matches)*
_ => return None
})
}
}
}
}
}

View file

@ -2,10 +2,11 @@ use prisma_client_rust_sdk::{
prelude::*,
prisma::prisma_models::walkers::{RefinedFieldWalker, RelationFieldWalker},
};
use prisma_models::walkers::{FieldWalker, ScalarFieldWalker};
use crate::{ModelSyncType, ModelWithSyncType};
pub fn r#enum(models: Vec<ModelWithSyncType>) -> TokenStream {
pub fn enumerate(models: &[ModelWithSyncType<'_>]) -> TokenStream {
let (variants, matches): (Vec<_>, Vec<_>) = models
.iter()
.filter_map(|(model, sync_type)| {
@ -38,193 +39,12 @@ pub fn r#enum(models: Vec<ModelWithSyncType>) -> TokenStream {
let match_arms = match sync_type.as_ref()? {
ModelSyncType::Shared { id, model_id } => {
let (get_id, equals_value, id_name_snake, create_id) = match id.refine() {
RefinedFieldWalker::Relation(rel) => {
let scalar_field = rel.fields().unwrap().next().unwrap();
let id_name_snake = snake_ident(scalar_field.name());
let field_name_snake = snake_ident(rel.name());
let opposite_model_name_snake =
snake_ident(rel.opposite_relation_field().unwrap().model().name());
let relation_equals_condition = quote!(prisma::#opposite_model_name_snake::pub_id::equals(
id.#field_name_snake.pub_id.clone()
));
let rel_fetch = quote! {
let rel = db.#opposite_model_name_snake()
.find_unique(#relation_equals_condition)
.exec()
.await?
.unwrap();
};
(
Some(rel_fetch),
quote!(rel.id),
id_name_snake,
relation_equals_condition,
)
}
RefinedFieldWalker::Scalar(s) => {
let field_name_snake = snake_ident(s.name());
let thing = quote!(id.#field_name_snake.clone());
(None, thing.clone(), field_name_snake, thing)
}
};
quote! {
#get_id
match data {
sd_sync::CRDTOperationData::Create(data) => {
let data: Vec<_> = data.into_iter().map(|(field, value)| {
prisma::#model_name_snake::SetParam::deserialize(&field, value).unwrap()
}).collect();
db.#model_name_snake()
.upsert(
prisma::#model_name_snake::#id_name_snake::equals(#equals_value),
prisma::#model_name_snake::create(#create_id, data.clone()),
data
)
.exec()
.await?;
},
sd_sync::CRDTOperationData::Update { field, value } => {
let data = vec![
prisma::#model_name_snake::SetParam::deserialize(&field, value).unwrap()
];
db.#model_name_snake()
.upsert(
prisma::#model_name_snake::#id_name_snake::equals(#equals_value),
prisma::#model_name_snake::create(#create_id, data.clone()),
data,
)
.exec()
.await?;
},
sd_sync::CRDTOperationData::Delete => {
db.#model_name_snake()
.delete(prisma::#model_name_snake::#id_name_snake::equals(#equals_value))
.exec()
.await?;
db.crdt_operation()
.delete_many(vec![
prisma::crdt_operation::model::equals(#model_id as i32),
prisma::crdt_operation::record_id::equals(rmp_serde::to_vec(&id).unwrap()),
prisma::crdt_operation::kind::equals(sd_sync::OperationKind::Create.to_string())
])
.exec()
.await?;
},
}
}
handle_crdt_ops_shared(id, *model_id, &model_name_snake)
}
ModelSyncType::Relation { item, group, .. } => {
let compound_id = format_ident!(
"{}",
group
.fields()
.unwrap()
.chain(item.fields().unwrap())
.map(|f| f.name())
.collect::<Vec<_>>()
.join("_")
);
let db_batch_items = {
let batch_item = |item: &RelationFieldWalker| {
let item_model_sync_id_field_name_snake = models
.iter()
.find(|m| m.0.name() == item.related_model().name())
.and_then(|(_m, sync)| sync.as_ref())
.map(|sync| snake_ident(sync.sync_id()[0].name()))
.unwrap();
let item_model_name_snake = snake_ident(item.related_model().name());
let item_field_name_snake = snake_ident(item.name());
quote! {
db.#item_model_name_snake()
.find_unique(
prisma::#item_model_name_snake::#item_model_sync_id_field_name_snake::equals(
id.#item_field_name_snake.#item_model_sync_id_field_name_snake.clone()
)
)
.select(prisma::#item_model_name_snake::select!({ id }))
}
};
[batch_item(group), batch_item(item)]
};
let create_items = {
let create_item = |item: &RelationFieldWalker, var: TokenStream| {
let item_model_name_snake = snake_ident(item.related_model().name());
quote!(
prisma::#item_model_name_snake::id::equals(#var.id)
)
};
[
create_item(item, quote!(item)),
create_item(group, quote!(group)),
]
};
quote! {
let (Some(group), Some(item)) =
(#(#db_batch_items.exec().await?),*) else {
panic!("item and group not found!");
};
let id = prisma::#model_name_snake::#compound_id(group.id, item.id);
match data {
sd_sync::CRDTOperationData::Create(_) => {
db.#model_name_snake()
.upsert(
id,
prisma::#model_name_snake::create(
#(#create_items),*,
vec![]
),
vec![],
)
.exec()
.await
.ok();
},
sd_sync::CRDTOperationData::Update { field, value } => {
let data = vec![prisma::#model_name_snake::SetParam::deserialize(&field, value).unwrap()];
db.#model_name_snake()
.upsert(
id,
prisma::#model_name_snake::create(
#(#create_items),*,
data.clone(),
),
data,
)
.exec()
.await
.ok();
},
sd_sync::CRDTOperationData::Delete => {
db.#model_name_snake()
.delete(id)
.exec()
.await
.ok();
},
}
}
handle_crdt_ops_relation(models, item, group, &model_name_snake)
}
_ => return None,
ModelSyncType::Local { .. } => return None,
};
Some(quote! {
@ -257,3 +77,210 @@ pub fn r#enum(models: Vec<ModelWithSyncType>) -> TokenStream {
}
}
}
fn handle_crdt_ops_relation(
models: &[ModelWithSyncType<'_>],
item: &RelationFieldWalker<'_>,
group: &RelationFieldWalker<'_>,
model_name_snake: &Ident,
) -> TokenStream {
let compound_id = format_ident!(
"{}",
group
.fields()
.expect("missing group fields")
.chain(item.fields().expect("missing item fields"))
.map(ScalarFieldWalker::name)
.collect::<Vec<_>>()
.join("_")
);
let db_batch_items = {
let batch_item = |item: &RelationFieldWalker<'_>| {
let item_model_sync_id_field_name_snake = models
.iter()
.find(|m| m.0.name() == item.related_model().name())
.and_then(|(_m, sync)| sync.as_ref())
.map(|sync| snake_ident(sync.sync_id()[0].name()))
.expect("missing sync id field name for relation");
let item_model_name_snake = snake_ident(item.related_model().name());
let item_field_name_snake = snake_ident(item.name());
quote! {
db.#item_model_name_snake()
.find_unique(
prisma::#item_model_name_snake::#item_model_sync_id_field_name_snake::equals(
id.#item_field_name_snake.#item_model_sync_id_field_name_snake.clone()
)
)
.select(prisma::#item_model_name_snake::select!({ id }))
}
};
[batch_item(group), batch_item(item)]
};
let create_items = {
let create_item = |item: &RelationFieldWalker<'_>, var: TokenStream| {
let item_model_name_snake = snake_ident(item.related_model().name());
quote!(
prisma::#item_model_name_snake::id::equals(#var.id)
)
};
[
create_item(item, quote!(item)),
create_item(group, quote!(group)),
]
};
quote! {
let (Some(group), Some(item)) =
(#(#db_batch_items.exec().await?),*) else {
panic!("item and group not found!");
};
let id = prisma::#model_name_snake::#compound_id(group.id, item.id);
match data {
sd_sync::CRDTOperationData::Create(_) => {
db.#model_name_snake()
.upsert(
id,
prisma::#model_name_snake::create(
#(#create_items),*,
vec![]
),
vec![],
)
.exec()
.await
.ok();
},
sd_sync::CRDTOperationData::Update { field, value } => {
let data = vec![prisma::#model_name_snake::SetParam::deserialize(&field, value).unwrap()];
db.#model_name_snake()
.upsert(
id,
prisma::#model_name_snake::create(
#(#create_items),*,
data.clone(),
),
data,
)
.exec()
.await
.ok();
},
sd_sync::CRDTOperationData::Delete => {
db.#model_name_snake()
.delete(id)
.exec()
.await
.ok();
},
}
}
}
#[inline]
fn handle_crdt_ops_shared(
id: &FieldWalker<'_>,
model_id: u16,
model_name_snake: &Ident,
) -> TokenStream {
let (get_id, equals_value, id_name_snake, create_id) = match id.refine() {
RefinedFieldWalker::Relation(rel) => {
let scalar_field = rel
.fields()
.expect("missing fields")
.next()
.expect("empty fields");
let id_name_snake = snake_ident(scalar_field.name());
let field_name_snake = snake_ident(rel.name());
let opposite_model_name_snake = snake_ident(
rel.opposite_relation_field()
.expect("missing opposite relation field")
.model()
.name(),
);
let relation_equals_condition = quote!(prisma::#opposite_model_name_snake::pub_id::equals(
id.#field_name_snake.pub_id.clone()
));
let rel_fetch = quote! {
let rel = db.#opposite_model_name_snake()
.find_unique(#relation_equals_condition)
.exec()
.await?
.unwrap();
};
(
Some(rel_fetch),
quote!(rel.id),
id_name_snake,
relation_equals_condition,
)
}
RefinedFieldWalker::Scalar(s) => {
let field_name_snake = snake_ident(s.name());
let thing = quote!(id.#field_name_snake.clone());
(None, thing.clone(), field_name_snake, thing)
}
};
quote! {
#get_id
match data {
sd_sync::CRDTOperationData::Create(data) => {
let data: Vec<_> = data.into_iter().map(|(field, value)| {
prisma::#model_name_snake::SetParam::deserialize(&field, value).unwrap()
}).collect();
db.#model_name_snake()
.upsert(
prisma::#model_name_snake::#id_name_snake::equals(#equals_value),
prisma::#model_name_snake::create(#create_id, data.clone()),
data
)
.exec()
.await?;
},
sd_sync::CRDTOperationData::Update { field, value } => {
let data = vec![
prisma::#model_name_snake::SetParam::deserialize(&field, value).unwrap()
];
db.#model_name_snake()
.upsert(
prisma::#model_name_snake::#id_name_snake::equals(#equals_value),
prisma::#model_name_snake::create(#create_id, data.clone()),
data,
)
.exec()
.await?;
},
sd_sync::CRDTOperationData::Delete => {
db.#model_name_snake()
.delete(prisma::#model_name_snake::#id_name_snake::equals(#equals_value))
.exec()
.await?;
db.crdt_operation()
.delete_many(vec![
prisma::crdt_operation::model::equals(#model_id as i32),
prisma::crdt_operation::record_id::equals(rmp_serde::to_vec(&id).unwrap()),
prisma::crdt_operation::kind::equals(sd_sync::OperationKind::Create.to_string())
])
.exec()
.await?;
},
}
}
}

View file

@ -169,7 +169,7 @@ export type CameraData = { device_make: string | null; device_model: string | nu
export type CasId = string
export type ChangeNodeNameArgs = { name: string | null; p2p_port: Port | null; p2p_disabled: boolean | null; p2p_ipv6_disabled: boolean | null; p2p_relay_disabled: boolean | null; p2p_discovery: P2PDiscoveryState | null; p2p_remote_access: boolean | null; p2p_manual_peers: string[] | null; image_labeler_version: string | null }
export type ChangeNodeNameArgs = { name: string | null; p2p_port: Port | null; p2p_disabled: boolean | null; p2p_ipv6_disabled: boolean | null; p2p_relay_disabled: boolean | null; p2p_discovery: P2PDiscoveryState | null; p2p_remote_access: boolean | null; p2p_manual_peers: string[] | null }
export type Chapter = { id: number; start: [number, number]; end: [number, number]; time_base_den: number; time_base_num: number; metadata: Metadata }