Module: Synthra::Mixin

Defined in:
lib/synthra/mixin.rb

Overview

Schema Mixin Support

Allows defining reusable field sets that can be included in multiple schemas. More flexible than inheritance for cross-cutting concerns.

Examples:

Define a mixin

@mixin Timestamps:
  created_at: timestamp
  updated_at: timestamp

Use in a schema

User:
  @include Timestamps
  id: uuid
  name: name

Defined Under Namespace

Classes: Registry

Class Method Summary collapse

Class Method Details

.apply(schema_node, mixin_names) ⇒ AST::SchemaNode

Apply mixins to a schema

Parameters:

  • schema_node (AST::SchemaNode)

    the schema node

  • mixin_names (Array<String>)

    names of mixins to include

Returns:

  • (AST::SchemaNode)

    schema with mixin fields added



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/synthra/mixin.rb', line 105

def self.apply(schema_node, mixin_names)
  return schema_node if mixin_names.empty?

  all_fields = []
  all_behaviors = schema_node.behaviors.dup

  # Add fields from each mixin (in order)
  mixin_names.each do |mixin_name|
    mixin = Registry.get(mixin_name)
    raise Errors::MixinError, "Unknown mixin: #{mixin_name}" unless mixin

    all_fields.concat(mixin[:fields])
    all_behaviors.concat(mixin[:behaviors])
  end

  # Add schema's own fields (override mixin fields if same name)
  existing_names = all_fields.map { |f| f.respond_to?(:name) ? f.name : f[:name] }
  schema_node.fields.each do |field|
    field_name = field.respond_to?(:name) ? field.name : field[:name]
    if existing_names.include?(field_name)
      # Replace mixin field with schema field
      all_fields.reject! { |f| (f.respond_to?(:name) ? f.name : f[:name]) == field_name }
    end
    all_fields << field
  end

  # Create new schema node with merged fields
  Parser::AST::SchemaNode.new(
    name: schema_node.name,
    fields: all_fields,
    behaviors: all_behaviors,
    parent_name: schema_node.parent_name,
    line: schema_node.line
  )
end