Skip to main content

ServiceDef

Struct ServiceDef 

Source
pub struct ServiceDef {
Show 18 fields pub name: String, pub display_name: Option<String>, pub description: Option<String>, pub fields: Vec<FieldDef>, pub actions: Vec<ActionDef>, pub guards: Vec<GuardDef>, pub relationships: Vec<RelationshipDef>, pub intent_hints: Vec<IntentHint>, pub state_machine: Option<StateMachine>, pub mcp_exposed: bool, pub tenant_column: Option<String>, pub mcp_ability: Option<String>, pub creatable: bool, pub updatable: bool, pub deletable: bool, pub mcp_write_ability: Option<String>, pub table: Option<String>, pub soft_delete_column: Option<String>,
}
Expand description

A service definition describing a domain entity and its fields.

Constructed via a builder API with method chaining:

use ferro_projections::{ServiceDef, DataType, FieldMeaning};

let order = ServiceDef::new("order")
    .display_name("Order")
    .description("Manages customer orders")
    .field("id", DataType::Integer, FieldMeaning::Identifier)
    .field("total", DataType::Float, FieldMeaning::Money)
    .optional_field("notes", DataType::String, FieldMeaning::FreeText);

Fields§

§name: String§display_name: Option<String>§description: Option<String>§fields: Vec<FieldDef>§actions: Vec<ActionDef>§guards: Vec<GuardDef>§relationships: Vec<RelationshipDef>§intent_hints: Vec<IntentHint>§state_machine: Option<StateMachine>§mcp_exposed: bool

Whether this projection is exposed as an MCP tool. Defaults to false. Only projections with mcp_exposed: true appear in a tools/list response.

§tenant_column: Option<String>

FK column name used to scope reads to a tenant. Plain metadata read by ferro-mcp-server dispatch; no auth dependency here.

§mcp_ability: Option<String>

Gate ability required to call this projection via MCP. Plain metadata read by the app’s MCP handler; no auth dependency here.

§creatable: bool

Whether create_<svc> is derived for this projection (Track A). Enabling any CRUD write verb requires mcp_write_ability (see validate).

§updatable: bool

Whether update_<svc> (data-field patch) is derived for this projection.

§deletable: bool

Whether delete_<svc> (soft-delete, confirmation-gated) is derived.

§mcp_write_ability: Option<String>

Gate ability required to call the create/update/delete tools. Required when any of creatable/updatable/deletable is set.

§table: Option<String>

Backing table name for derived CRUD dispatch (field→column binding). When None, the dispatch layer derives it from the service name.

§soft_delete_column: Option<String>

Soft-delete column name. When None, the dispatch layer defaults to deleted_at.

Implementations§

Source§

impl ServiceDef

Source

pub fn new(name: impl Into<String>) -> Self

Creates a new service definition with the given name.

Source

pub fn display_name(self, name: impl Into<String>) -> Self

Sets the human-readable display name.

Source

pub fn description(self, desc: impl Into<String>) -> Self

Sets the service description.

Source

pub fn mcp_exposed(self, exposed: bool) -> Self

Marks this projection as MCP-exposed.

Source

pub fn tenant_column(self, col: impl Into<String>) -> Self

Declares the FK column name used to scope reads to a tenant. Plain metadata read by ferro-mcp-server dispatch; no auth dependency here.

Source

pub fn mcp_ability(self, ability: impl Into<String>) -> Self

Declares the Gate ability required to call this projection via MCP. Plain metadata read by the app’s MCP handler; no auth dependency here.

Source

pub fn creatable(self, yes: bool) -> Self

Enables derivation of create_<svc>. Requires mcp_write_ability (Track A).

Source

pub fn updatable(self, yes: bool) -> Self

Enables derivation of update_<svc> (data-field patch). Requires mcp_write_ability.

Source

pub fn deletable(self, yes: bool) -> Self

Enables derivation of delete_<svc> (soft-delete, confirmation-gated). Requires mcp_write_ability.

Source

pub fn mcp_write_ability(self, ability: impl Into<String>) -> Self

Declares the Gate ability required to call create/update/delete tools.

Source

pub fn table(self, table: impl Into<String>) -> Self

Declares the backing table for derived CRUD dispatch (field→column binding).

Source

pub fn soft_delete_column(self, col: impl Into<String>) -> Self

Declares the soft-delete column (defaults to deleted_at when unset).

Source

pub fn resolved_table(&self) -> String

Returns the backing table name: explicit .table() value or the default format!("{}s", name.to_lowercase()).

Matches the inline derivation previously at dispatch.rs:123 — the default MUST stay byte-identical or existing projections query the wrong table.

Source

pub fn resolved_soft_delete_column(&self) -> &str

Returns the soft-delete column name: explicit .soft_delete_column() value or the default "deleted_at".

Source

pub fn is_server_injected_field(&self, field: &FieldDef) -> bool

Returns true if the field must be server-injected and never an agent input.

Covers:

  • Identifier fields (primary key — set by DB auto-increment)
  • CreatedAt fields (set by DB DEFAULT current_timestamp)
  • The tenant column (injected from McpContext, never from agent payload)

This is the schema-derivation boundary Phase 240 consumes to exclude these fields from derived write input schemas (T-239-01 mitigation substrate).

Source

pub fn is_write_excluded_field( &self, field: &FieldDef, exclude_sm_status: bool, ) -> bool

Returns true if a field must be excluded from write input schemas (create and update). Composes Self::is_server_injected_field and adds UpdatedAt, Sensitive, and list-field exclusions.

exclude_sm_status: callers pass self.state_machine.is_some(); when true, a Status field is also excluded because the StateMachine sets it server-side to the initial state.

Source

pub fn field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self

Adds a required read-write field.

Source

pub fn field_with_hint( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, hint: RenderHint, ) -> Self

Adds a required read-write field carrying a non-visual RenderHint.

Use for Url/ImageUrl fields whose raw value has no useful text form: RenderHint::AltText(s) substitutes s, RenderHint::Skip omits the field from non-visual output. The visual renderer ignores the hint.

Source

pub fn optional_field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self

Adds an optional (nullable) read-write field.

Source

pub fn list_field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self

Adds a required read-write list field.

Source

pub fn read_only_field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self

Adds a required read-only field (readable but not writable).

For system-assigned or computed fields like id, created_at, or totals.

Source

pub fn write_only_field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self

Adds a required write-only field (writable but not readable).

For sensitive inputs like passwords or API keys that should not be read back.

Source

pub fn action(self, action: ActionDef) -> Self

Adds an action definition to this service.

Source

pub fn guard(self, guard: GuardDef) -> Self

Adds a guard definition to this service.

Source

pub fn relationship(self, rel: RelationshipDef) -> Self

Adds a relationship definition to this service.

Source

pub fn belongs_to( self, name: impl Into<String>, target: impl Into<String>, ) -> Self

Adds a many-to-one relationship (this service belongs to target).

Source

pub fn has_many( self, name: impl Into<String>, target: impl Into<String>, ) -> Self

Adds a one-to-many relationship (this service has many of target).

Source

pub fn has_one(self, name: impl Into<String>, target: impl Into<String>) -> Self

Adds a one-to-one relationship (this service has one of target).

Source

pub fn belongs_to_many( self, name: impl Into<String>, target: impl Into<String>, ) -> Self

Adds a many-to-many relationship (this service belongs to many of target).

Source

pub fn intent_hint(self, hint: IntentHint) -> Self

Adds an intent hint for overriding structural derivation.

Source

pub fn state_machine(self, machine: StateMachine) -> Self

Sets the state machine definition for this service.

Source

pub fn from_model(meta: &ModelMetadata) -> Self

Derives a ServiceDef from model metadata.

Infers DataType from column type strings and FieldMeaning from field names. System fields (id, created_at, updated_at, primary keys) are marked read-only. Actions, state machines, and relationships are not derived.

Source

pub fn validate(&self) -> Result<Vec<Warning>, Error>

Validates the service definition and returns warnings for potential issues.

This is the single validation entry point that subsumes StateMachine::validate(). Guard names form a shared pool referenced from transitions and action preconditions.

Returns Err for fatal issues (undefined guard references, unmatched triggers). Returns Ok(warnings) for structural concerns (unused guards, missing state machine).

Trait Implementations§

Source§

impl Clone for ServiceDef

Source§

fn clone(&self) -> ServiceDef

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ServiceDef

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for ServiceDef

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl JsonSchema for ServiceDef

Source§

fn schema_name() -> Cow<'static, str>

The name of the generated JSON Schema. Read more
Source§

fn schema_id() -> Cow<'static, str>

Returns a string that uniquely identifies the schema produced by this type. Read more
Source§

fn json_schema(generator: &mut SchemaGenerator) -> Schema

Generates a JSON Schema for this type. Read more
Source§

fn inline_schema() -> bool

Whether JSON Schemas generated for this type should be included directly in parent schemas, rather than being re-used where possible using the $ref keyword. Read more
Source§

impl PartialEq for ServiceDef

Source§

fn eq(&self, other: &ServiceDef) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for ServiceDef

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for ServiceDef

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.