Skip to content

Commit 72169be

Browse files
committed
fix(grpc): preserve pre-deletion model values for MemberClause filter matching
1 parent eef820a commit 72169be

8 files changed

Lines changed: 174 additions & 1893 deletions

File tree

crates/grpc/server/src/subscriptions/entity.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,19 @@ impl Service {
128128
continue;
129129
}
130130

131+
// When deleted, use match_model which preserves the entity's model values
132+
// before deletion for MemberClause matching
133+
// cc. fix(grpc): preserve pre-deletion model values for MemberClause filter…#407
134+
let model_for_matching = if let Some(match_model) = &entity.match_model {
135+
Some(match_model.clone())
136+
} else {
137+
entity.entity.models.first().map(|m| Ty::Struct(m.clone()))
138+
};
139+
131140
if !match_entity(
132141
entity.entity.hashed_keys,
133142
&entity.keys,
134-
&entity.entity.models.first().map(|m| Ty::Struct(m.clone())),
143+
&model_for_matching,
135144
clause,
136145
) {
137146
continue;

crates/grpc/server/src/subscriptions/event_message.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,19 @@ impl Service {
131131
continue;
132132
}
133133

134+
// When deleted, use match_model which preserves the entity's model values
135+
// before deletion for MemberClause matching
136+
// cc. fix(grpc): preserve pre-deletion model values for MemberClause filter…#407
137+
let model_for_matching = if let Some(match_model) = &event.match_model {
138+
Some(match_model.clone())
139+
} else {
140+
event.entity.models.first().map(|m| Ty::Struct(m.clone()))
141+
};
142+
134143
if !match_entity(
135144
event.entity.hashed_keys,
136145
&event.keys,
137-
&event.entity.models.first().map(|m| Ty::Struct(m.clone())),
146+
&model_for_matching,
138147
clause,
139148
) {
140149
continue;

crates/grpc/server/src/subscriptions/mod.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,107 @@ pub(crate) fn match_keys(keys: &[Felt], clauses: &[KeysClause]) -> bool {
383383

384384
true
385385
}
386+
387+
#[cfg(test)]
388+
mod tests {
389+
use super::*;
390+
use dojo_types::primitive::Primitive;
391+
use dojo_types::schema::{Member, Struct, Ty};
392+
use torii_proto::MemberClause;
393+
394+
fn create_test_model(name: &str, score: u32) -> Ty {
395+
Ty::Struct(Struct {
396+
name: name.to_string(),
397+
children: vec![Member {
398+
name: "score".to_string(),
399+
ty: Ty::Primitive(Primitive::U32(Some(score))),
400+
key: false,
401+
}],
402+
})
403+
}
404+
405+
#[test]
406+
fn test_member_clause_matches_deletion_with_matching_value() {
407+
let id = Felt::from(1u64);
408+
let keys = vec![Felt::from(1u64), Felt::from(2u64)];
409+
let model = Some(create_test_model("Game-Player", 150));
410+
411+
let clause = Clause::Member(MemberClause {
412+
model: "Game-Player".to_string(),
413+
member: "score".to_string(),
414+
operator: ComparisonOperator::Gte,
415+
value: MemberValue::Primitive(Primitive::U32(Some(100))),
416+
});
417+
418+
assert!(match_entity(id, &keys, &model, &clause));
419+
}
420+
421+
#[test]
422+
fn test_member_clause_rejects_deletion_with_non_matching_value() {
423+
let id = Felt::from(1u64);
424+
let keys = vec![Felt::from(1u64), Felt::from(2u64)];
425+
let model = Some(create_test_model("Game-Player", 50));
426+
427+
let clause = Clause::Member(MemberClause {
428+
model: "Game-Player".to_string(),
429+
member: "score".to_string(),
430+
operator: ComparisonOperator::Gte,
431+
value: MemberValue::Primitive(Primitive::U32(Some(100))),
432+
});
433+
434+
assert!(!match_entity(id, &keys, &model, &clause));
435+
}
436+
437+
#[test]
438+
fn test_member_clause_with_none_model_returns_false() {
439+
let id = Felt::from(1u64);
440+
let keys = vec![Felt::from(1u64), Felt::from(2u64)];
441+
let model: Option<Ty> = None;
442+
443+
let clause = Clause::Member(MemberClause {
444+
model: "Game-Player".to_string(),
445+
member: "score".to_string(),
446+
operator: ComparisonOperator::Gte,
447+
value: MemberValue::Primitive(Primitive::U32(Some(100))),
448+
});
449+
450+
assert!(!match_entity(id, &keys, &model, &clause));
451+
}
452+
453+
#[test]
454+
fn test_keys_clause_matches_deletion() {
455+
let id = Felt::from(1u64);
456+
let keys = vec![Felt::from(1u64), Felt::from(2u64)];
457+
let model = Some(create_test_model("Game-Player", 100));
458+
459+
let clause = Clause::Keys(KeysClause {
460+
keys: vec![Some(Felt::from(1u64)), None],
461+
pattern_matching: PatternMatching::VariableLen,
462+
models: vec![],
463+
});
464+
465+
assert!(match_entity(id, &keys, &model, &clause));
466+
}
467+
468+
#[test]
469+
fn test_hashed_keys_clause_matches_deletion() {
470+
let id = Felt::from(123u64);
471+
let keys = vec![Felt::from(1u64), Felt::from(2u64)];
472+
let model = Some(create_test_model("Game-Player", 100));
473+
474+
let clause = Clause::HashedKeys(vec![Felt::from(123u64), Felt::from(456u64)]);
475+
476+
assert!(match_entity(id, &keys, &model, &clause));
477+
}
478+
479+
#[test]
480+
fn test_hashed_keys_clause_rejects_non_matching_id() {
481+
let id = Felt::from(789u64);
482+
let keys = vec![Felt::from(1u64), Felt::from(2u64)];
483+
let model = Some(create_test_model("Game-Player", 100));
484+
485+
let clause = Clause::HashedKeys(vec![Felt::from(123u64), Felt::from(456u64)]);
486+
487+
assert!(!match_entity(id, &keys, &model, &clause));
488+
}
489+
}

0 commit comments

Comments
 (0)