use type_bridge_core_lib::ast::{Clause, Constraint, FetchItem, Pattern, RolePlayer, Statement};
use serde::Serialize;
use crate::entity::OwnedAttributeInfo;
use crate::error::Result;
use crate::filter::Filter;
use crate::value::AttributeValue;
#[derive(Debug, Clone, Serialize)]
pub struct RoleInfo {
pub role_name: &'static str,
pub player_type_name: &'static str,
}
#[derive(Debug, Clone, Serialize)]
pub struct RolePlayerRef {
pub role: &'static str,
pub entity_type_name: &'static str,
pub iid: Option<String>,
pub key: Option<(&'static str, AttributeValue)>,
}
impl RolePlayerRef {
fn to_match_pattern(&self, var: &str) -> Pattern {
let mut constraints = Vec::new();
if let Some(ref iid) = self.iid {
constraints.push(Constraint::Iid(iid.clone()));
} else if let Some((attr_name, ref value)) = self.key {
constraints.push(Constraint::Has {
attr_name: attr_name.to_string(),
value: value.to_ast_value(),
});
}
Pattern::Entity {
variable: var.to_string(),
type_name: self.entity_type_name.to_string(),
constraints,
is_strict: false,
}
}
}
pub trait TypeBridgeRelation: Sized + Send + Sync + 'static {
const TYPE_NAME: &'static str;
const IS_ABSTRACT: bool = false;
const PARENT_TYPE: Option<&'static str> = None;
fn owned_attributes() -> &'static [OwnedAttributeInfo];
fn role_info() -> &'static [RoleInfo];
fn iid(&self) -> Option<&str>;
fn set_iid(&mut self, iid: String);
fn to_attribute_values(&self) -> Vec<(&'static str, AttributeValue)>;
fn to_role_player_refs(&self) -> Vec<RolePlayerRef>;
fn from_document(doc: &serde_json::Map<String, serde_json::Value>) -> Result<Self>;
fn to_insert_clauses(&self, var: &str) -> Vec<Clause> {
let role_refs = self.to_role_player_refs();
let match_patterns: Vec<Pattern> = role_refs
.iter()
.enumerate()
.map(|(i, rp)| rp.to_match_pattern(&format!("$rp{i}")))
.collect();
let role_players: Vec<RolePlayer> = role_refs
.iter()
.enumerate()
.map(|(i, rp)| RolePlayer {
role: rp.role.to_string(),
player_var: format!("$rp{i}"),
})
.collect();
let attributes: Vec<Statement> = self
.to_attribute_values()
.into_iter()
.map(|(attr_name, value)| Statement::Has {
subject_var: var.to_string(),
attr_name: attr_name.to_string(),
value: value.to_ast_value(),
})
.collect();
let mut clauses = Vec::new();
if !match_patterns.is_empty() {
clauses.push(Clause::Match(match_patterns));
}
clauses.push(Clause::Insert(vec![Statement::Relation {
variable: var.to_string(),
type_name: Self::TYPE_NAME.to_string(),
role_players,
include_variable: true,
attributes,
}]));
clauses
}
fn to_insert_with_iid_fetch(&self, var: &str) -> Vec<Clause> {
let mut clauses = self.to_insert_clauses(var);
clauses.push(Clause::Fetch(vec![FetchItem::Function {
key: "iid".to_string(),
func_name: "iid".to_string(),
var: var.to_string(),
}]));
clauses
}
fn identification_constraints(&self) -> Vec<Constraint> {
if let Some(iid) = self.iid() {
return vec![Constraint::Iid(iid.to_string())];
}
vec![]
}
fn to_match_pattern(&self, var: &str) -> Vec<Pattern> {
if let Some(iid) = self.iid() {
return vec![Pattern::Relation {
variable: var.to_string(),
type_name: Self::TYPE_NAME.to_string(),
role_players: vec![],
constraints: vec![Constraint::Iid(iid.to_string())],
}];
}
let role_refs = self.to_role_player_refs();
let mut patterns = Vec::new();
for (i, rp) in role_refs.iter().enumerate() {
patterns.push(rp.to_match_pattern(&format!("$rp{i}")));
}
let rp_bindings: Vec<RolePlayer> = role_refs
.iter()
.enumerate()
.map(|(i, rp)| RolePlayer {
role: rp.role.to_string(),
player_var: format!("$rp{i}"),
})
.collect();
let attr_constraints: Vec<Constraint> = self
.to_attribute_values()
.into_iter()
.map(|(attr_name, value)| Constraint::Has {
attr_name: attr_name.to_string(),
value: value.to_ast_value(),
})
.collect();
patterns.push(Pattern::Relation {
variable: var.to_string(),
type_name: Self::TYPE_NAME.to_string(),
role_players: rp_bindings,
constraints: attr_constraints,
});
patterns
}
fn build_polymorphic_fetch(var: &str, type_name: &str, filters: &[Filter]) -> Vec<Clause> {
let constraints: Vec<Constraint> = filters
.iter()
.map(|f| Constraint::Has {
attr_name: f.attr_name.clone(),
value: f.value.to_ast_value(),
})
.collect();
let match_patterns = vec![
Pattern::Relation {
variable: var.to_string(),
type_name: "$t".to_string(),
role_players: vec![],
constraints,
},
Pattern::SubType {
variable: "$t".to_string(),
parent_type: type_name.to_string(),
},
];
let fetch_items = vec![
FetchItem::Function {
key: "_iid".to_string(),
func_name: "iid".to_string(),
var: var.to_string(),
},
FetchItem::Function {
key: "_type".to_string(),
func_name: "label".to_string(),
var: "$t".to_string(),
},
FetchItem::NestedWildcard {
key: "attributes".to_string(),
var: var.to_string(),
},
];
vec![Clause::Match(match_patterns), Clause::Fetch(fetch_items)]
}
}