Derive Macro qualia_derive::ObjectShape

source ·
#[derive(ObjectShape)]
{
    // Attributes available to this derive:
    #[field]
    #[fixed_fields]
    #[rest_fields]
    #[related]
    #[referenced]
}
Expand description

Automatically translate between properties of Qualia objects and fields of structs.

Basic example

#[derive(Debug, ObjectShape, PartialEq)]
struct CustomShape {
    name: String,
    width: i64,
}

let shape: Object = CustomShape {
    name: "letter".to_string(),
    width: 8,
}
.into();

assert_eq!(
    shape,
    object!("name" => "letter", "width" => 8),
);

let obj: Object = object!(
    "name" => "letter",
    "width" => 8,
);

assert_eq!(
    CustomShape::try_from(obj),
    Ok(CustomShape {
        name: "letter".to_string(),
        width: 8,
    })
);

Renaming properties

By default, properties get the same name as the field in the struct. This can be changed with the field attribute:

#[derive(Debug, ObjectShape, PartialEq)]
struct CustomShape {
    #[field("my-name")]
    name: String,
    width: i64,
}

let shape: Object = CustomShape {
    name: "letter".to_string(),
    width: 8,
}
.into();

assert_eq!(
    shape,
    object!("my-name" => "letter", "width" => 8),
);

Adding fixed properties

Additional fields with fixed values can be added with the fixed_fields attribute on the struct:

#[derive(Debug, ObjectShape, PartialEq)]
#[fixed_fields("kind" => "custom")]
struct CustomShape {
    width: i64,
    height: i64,
}

let shape: Object = CustomShape {
    width: 8,
    height: 11,
}
.into();

assert_eq!(
    shape,
    object!("kind" => "custom", "width" => 8, "height" => 11),
);

There is a helper method provided, q(), which makes use of these fields. For example, for the above object shape, CustomShape::q returns a query for "kind" = "custom".

Accessing other properties

To set and fetch unlisted properties, an Object field with the rest_fields attribute may be added.

#[derive(Debug, ObjectShape, PartialEq)]
struct CustomShape {
    width: i64,
    #[rest_fields]
    rest: Object,
}

let shape: Object = CustomShape {
    width: 8,
    rest: object!("height" => "tall"),
}
.into();

assert_eq!(
    shape,
    object!("width" => 8, "height" => "tall"),
);

Getting ID of inserted object

The ID of the object can be retrieved from an Option<i64> field named object_id:

#[derive(Debug, ObjectShape, PartialEq)]
struct CustomShape {
    object_id: Option<i64>,
    width: i64,
}

let shape: CustomShape = object!(
    "object_id" => 42,
    "width" => 65,
).try_into().unwrap();

assert_eq!(
    shape,
    CustomShape { object_id: Some(42), width: 65 },
);

// let shape2 = CustomShape { object_id: None, width: 11 };
// store.insert_with_id(&mut shape2)?;
// assert!(shape2.object_id.is_some());

Often, objects contain references to other object’s ID fields. If those objects have a defined ObjectShape, then helper methods to fetch them can be generated with the related attribute:

#[derive(Debug, ObjectShape, PartialEq)]
struct ShapeGroup {
    object_id: Option<i64>,
    name: String,
}

#[derive(Debug, ObjectShape, PartialEq)]
struct CustomShape {
    #[related(ShapeGroup)]
    shape_group_id: i64,
    width: i64,
}

// if let Some(group) = custom_shape.fetch_shape_group(&store)? {;
//     ...