Module: Synthra::SchemaInference

Defined in:
lib/synthra/rails_test_helper.rb

Overview

Schema Inference from ActiveRecord models

Automatically generates Synthra schemas from ActiveRecord models by inspecting column types, validations, and associations.

Class Method Summary collapse

Class Method Details

.from_active_record(model) ⇒ String

Generate DSL from ActiveRecord model

Parameters:

  • model (Class)

    ActiveRecord model class

Returns:

  • (String)

    DSL string



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/synthra/rails_test_helper.rb', line 139

def from_active_record(model)
  lines = ["#{model.name}:"]
  
  model.columns.each do |column|
    next if skip_column?(column.name)
    
    type = infer_type_from_column(column, model)
    optional = column.null ? "?" : ""
    lines << "  #{column.name}#{optional}: #{type}"
  end
  
  lines.join("\n")
end

.infer_dsl(name) ⇒ String

Generate minimal DSL from schema name

Parameters:

  • name (String)

    schema name

Returns:

  • (String)

    DSL string



158
159
160
161
162
163
# File 'lib/synthra/rails_test_helper.rb', line 158

def infer_dsl(name)
  <<~DSL
    #{name}:
      id: uuid
  DSL
end

.infer_string_type(column, model) ⇒ Object (private)



210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/synthra/rails_test_helper.rb', line 210

def infer_string_type(column, model)
  # Check for enum
  if model.respond_to?(:defined_enums) && model.defined_enums.key?(column.name.to_s)
    values = model.defined_enums[column.name.to_s].keys
    return "enum(#{values.join(', ')})"
  end
  
  # Check for length constraint
  if column.limit && column.limit <= 50
    "text(1..#{column.limit})"
  else
    "text"
  end
end

.infer_type_from_column(column, model) ⇒ Object (private)



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/synthra/rails_test_helper.rb', line 171

def infer_type_from_column(column, model)
  # Check for specific patterns in column name
  name = column.name.to_s
  
  return "email" if name.include?("email")
  return "phone" if name.include?("phone")
  return "url" if name.include?("url") || name.include?("link")
  return "uuid" if name.end_with?("_id") || name == "uuid"
  return "password" if name.include?("password")
  return "name" if name == "name" || name.end_with?("_name")
  return "address" if name.include?("address")
  return "city" if name == "city"
  return "state" if name == "state"
  return "country" if name == "country"
  return "postal_code" if name.include?("zip") || name.include?("postal")
  
  # Fall back to column type
  case column.type
  when :string, :text
    infer_string_type(column, model)
  when :integer, :bigint
    "number"
  when :float, :decimal
    "money"
  when :boolean
    "boolean"
  when :date
    "date"
  when :datetime, :timestamp
    "timestamp"
  when :uuid
    "uuid"
  when :json, :jsonb
    "object"
  else
    "text"
  end
end

.skip_column?(name) ⇒ Boolean (private)

Returns:

  • (Boolean)


167
168
169
# File 'lib/synthra/rails_test_helper.rb', line 167

def skip_column?(name)
  %w[id created_at updated_at].include?(name.to_s)
end