wip reciprocal relation names

master
Ondřej Hruška 3 years ago
parent efbfecc335
commit cd82d5465a
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      yopa-web/resources/templates/index.html.tera
  2. 3
      yopa-web/resources/templates/relation_create.html.tera
  3. 2
      yopa-web/src/main.rs
  4. 2
      yopa-web/src/routes.rs
  5. 16
      yopa/src/lib.rs
  6. 2
      yopa/src/model.rs

@ -45,7 +45,7 @@
<ul>
{% for rel in model.relations %}
<li>
<span title="{{rel.model.id}}">"{{rel.model.name}}", pointing to: <i>{{rel.related_name}}</i></span>
<span title="{{rel.model.id}}">"{{rel.model.name}}", pointing to: <i>{{rel.related_name}}</i> (reciprocal as "{{rel.model.reciprocal_name}}")</span>
{%- if rel.model.optional %}, OPTIONAL{% endif %}
{%- if rel.model.multiple %}, MULTIPLE{% endif %}
<br>

@ -20,6 +20,9 @@ Define relation
<label for="name">Name:</label>
<input type="text" id="name" name="name"><br>
<label for="reciprocal_name">Reciprocal name:</label>
<input type="text" id="reciprocal_name" name="reciprocal_name"><br>
<label for="optional">Optional:</label>
<input type="checkbox" name="optional" id="optional" value="1">
<br>

@ -168,6 +168,7 @@ fn init_yopa() -> YopaStoreWrapper {
id: Default::default(),
object: id_recipe,
name: "book reference".to_string(),
reciprocal_name: "recipes".to_string(),
optional: true,
multiple: true,
related: id_book
@ -187,6 +188,7 @@ fn init_yopa() -> YopaStoreWrapper {
id: Default::default(),
object: id_recipe,
name: "related recipe".to_string(),
reciprocal_name: "related recipe".to_string(),
optional: true,
multiple: true,
related: id_recipe

@ -178,6 +178,7 @@ pub(crate) async fn relation_model_create_form(
pub(crate) struct RelationModelCreate {
pub object : ID,
pub name : String,
pub reciprocal_name : String,
pub optional : Option<i32>,
pub multiple : Option<i32>,
pub related : ID,
@ -195,6 +196,7 @@ pub(crate) async fn relation_model_create(
id: Default::default(),
object: form.object,
name: form.name.clone(),
reciprocal_name: form.reciprocal_name.clone(),
optional: form.optional.unwrap_or_default() != 0,
multiple: form.multiple.unwrap_or_default() != 0,
related: form.related

@ -92,12 +92,22 @@ impl Storage {
return Err(StorageError::NotExist(format!("related object model {}", rel.related).into()));
}
if self.rel_models.iter().find(|(_, t)| t.name == rel.name && t.object == rel.object).is_some() {
if let Some((_, colliding)) = self.rel_models.iter().find(|(_, other)| {
(other.name == rel.name && other.object == rel.object) // Exact match
|| (other.name == rel.reciprocal_name && other.object == rel.related) // Our reciprocal name collides with related's own relation name
|| (other.reciprocal_name == rel.name && other.related == rel.object) // Our name name collides with a reciprocal name on the other relation
|| (other.reciprocal_name == rel.reciprocal_name && other.related == rel.related) // Reciprocal names collide for the same destination
}) {
return Err(StorageError::ConstraintViolation(
format!("relation with the name \"{}\" and on model {} already exists", rel.name, rel.object).into()));
format!("name collision (\"{}\" / \"{}\") with existing relation (\"{}\" / \"{}\")",
rel.name, rel.reciprocal_name,
colliding.name, colliding.reciprocal_name
).into()));
}
debug!("Define relation model \"{}\" from {} to {}", rel.name, self.describe_model(rel.object), self.describe_model(rel.related));
debug!("Define relation model \"{}\" from {} to {}, reciprocal name \"{}\"",
rel.name, self.describe_model(rel.object), self.describe_model(rel.related), rel.reciprocal_name);
let id = next_id();
rel.id = id;
self.rel_models.insert(id, rel);

@ -35,6 +35,8 @@ pub struct RelationModel {
pub object: ID,
/// Relation name, unique within the parent object
pub name: String,
/// Relation name when viewed from the other side, unique within the related object's relations
pub reciprocal_name: String,
/// Relation is optional
pub optional: bool,
/// Relation can be multiple

Loading…
Cancel
Save