Class: LcpRuby::Metadata::FieldDefinition

Inherits:
Object
  • Object
show all
Defined in:
lib/lcp_ruby/metadata/field_definition.rb

Constant Summary collapse

BASE_TYPES =
%w[
  string text integer float decimal boolean
  date datetime enum file rich_text json uuid
  attachment array
].freeze
VALID_ARRAY_ITEM_TYPES =
%w[string integer float].freeze
VALID_TYPES =

Backward compatibility

BASE_TYPES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs = {}) ⇒ FieldDefinition

Returns a new instance of FieldDefinition.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 20

def initialize(attrs = {})
  @name = attrs[:name].to_s
  @type = attrs[:type].to_s
  @label = attrs[:label] || @name.humanize
  @column_options = attrs[:column_options] || {}
  @validations = (attrs[:validations] || []).map { |v| ValidationDefinition.new(v) }
  @enum_values = attrs[:enum_values] || []
  @default = attrs[:default]
  @transforms = Array(attrs[:transforms]).map(&:to_s)
  @computed = attrs[:computed]
  @attachment_options = attrs[:attachment_options] || {}
  @source = attrs[:source]
  @item_type = attrs[:item_type]&.to_s
  @sequence = normalize_sequence(attrs[:sequence])
  @lcp_managed = attrs[:lcp_managed] == true
  # i18n_check Phase 3a — captured in ModelBuilder#field for DSL,
  # nil for YAML-loaded fields (Pass 3 covers YAML).
  @label_source_loc = attrs[:label_source_loc]

  validate!
  resolve_type_definition!
end

Instance Attribute Details

#attachment_optionsObject (readonly)

Returns the value of attribute attachment_options.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def attachment_options
  @attachment_options
end

#column_optionsObject (readonly)

Returns the value of attribute column_options.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def column_options
  @column_options
end

#computedObject (readonly)

Returns the value of attribute computed.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def computed
  @computed
end

#defaultObject (readonly)

Returns the value of attribute default.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def default
  @default
end

#enum_valuesObject (readonly)

Returns the value of attribute enum_values.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def enum_values
  @enum_values
end

#item_typeObject (readonly)

Returns the value of attribute item_type.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def item_type
  @item_type
end

#labelObject (readonly)

Returns the value of attribute label.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def label
  @label
end

#label_source_locObject (readonly)

Returns the value of attribute label_source_loc.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def label_source_loc
  @label_source_loc
end

#lcp_managedObject (readonly)

Returns the value of attribute lcp_managed.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def lcp_managed
  @lcp_managed
end

#nameObject (readonly)

Returns the value of attribute name.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def name
  @name
end

#sequenceObject (readonly)

Returns the value of attribute sequence.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def sequence
  @sequence
end

#sourceObject (readonly)

Returns the value of attribute source.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def source
  @source
end

#transformsObject (readonly)

Returns the value of attribute transforms.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def transforms
  @transforms
end

#typeObject (readonly)

Returns the value of attribute type.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def type
  @type
end

#type_definitionObject (readonly)

Returns the value of attribute type_definition.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def type_definition
  @type_definition
end

#validationsObject (readonly)

Returns the value of attribute validations.



15
16
17
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 15

def validations
  @validations
end

Class Method Details

.from_hash(hash) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 43

def self.from_hash(hash)
  new(
    name: hash["name"],
    type: hash["type"],
    label: hash["label"],
    column_options: symbolize_keys(hash["column_options"]),
    validations: hash["validations"],
    enum_values: hash["enum_values"],
    default: hash["default"],
    transforms: hash["transforms"],
    computed: hash["computed"],
    attachment_options: hash["options"] || {},
    source: hash["source"],
    item_type: hash["item_type"],
    sequence: hash["sequence"],
    lcp_managed: hash["lcp_managed"],
    label_source_loc: hash["_label_source_loc"]
  )
end

.symbolize_keys(hash) ⇒ Object



261
262
263
264
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 261

def self.symbolize_keys(hash)
  return {} unless hash.is_a?(Hash)
  hash.transform_keys(&:to_sym)
end

Instance Method Details

#array?Boolean

Returns:

  • (Boolean)


140
141
142
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 140

def array?
  type == "array"
end

#attachment?Boolean

Returns:

  • (Boolean)


136
137
138
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 136

def attachment?
  type == "attachment"
end

#attachment_multiple?Boolean

Returns:

  • (Boolean)


144
145
146
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 144

def attachment_multiple?
  attachment? && attachment_options["multiple"] == true
end

#column_typeObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 87

def column_type
  return nil if attachment?
  return nil if virtual?

  if array?
    if LcpRuby.postgresql?
      pg_array_column_type
    else
      LcpRuby.json_column_type
    end
  elsif @type_definition
    @type_definition.column_type
  else
    case type
    when "enum" then :string
    when "rich_text" then :text
    when "uuid" then :string
    when "json" then LcpRuby.json_column_type
    when "file" then :string
    else type.to_sym
    end
  end
end

#computed?Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 67

def computed?
  !!@computed
end

#effective_column_optionsObject

Schema-level column options (limit / precision / scale / null) after overlaying type defaults with field-level overrides. Mirrors the logic in SchemaManager#build_column_options so the validator’s collision check sees the same shape SchemaManager would emit at add_column time. Default values (the second half of build_column _options’ work) are NOT included here — the validator only needs the schema-shape sub-options.



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 181

def effective_column_options
  opts = {}
  type_opts = type_definition&.column_options || {}
  col_opts = column_options || {}

  opts[:limit] = type_opts[:limit] if type_opts[:limit]
  opts[:precision] = type_opts[:precision] if type_opts[:precision]
  opts[:scale] = type_opts[:scale] if type_opts[:scale]
  opts[:null] = type_opts[:null] if type_opts.key?(:null)

  opts[:limit] = col_opts[:limit] if col_opts[:limit]
  opts[:precision] = col_opts[:precision] if col_opts[:precision]
  opts[:scale] = col_opts[:scale] if col_opts[:scale]
  opts[:null] = col_opts[:null] if col_opts.key?(:null)

  opts
end

#enum?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 132

def enum?
  type == "enum"
end

#enum_label_for(value, model_name: nil) ⇒ Object

Resolves the display label for an enum value. Priority: i18n translation (enums.* or models..enums.) > explicit YAML label > humanize fallback.



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 154

def enum_label_for(value, model_name: nil)
  key = value.to_s
  return key.humanize if key.blank?

  if model_name.present?
    result = I18n.t("lcp_ruby.enums.#{model_name}.#{name}.#{key}", default: nil)
    return result if result

    result = I18n.t("lcp_ruby.models.#{model_name}.enums.#{name}.#{key}", default: nil)
    return result if result
  end

  ev = enum_values.find { |v| v.is_a?(Hash) && (v["value"] || v[:value]).to_s == key }
  if ev.is_a?(Hash) && (ev["label"] || ev[:label])
    return (ev["label"] || ev[:label]).to_s
  end

  key.humanize
end

#enum_value_namesObject



148
149
150
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 148

def enum_value_names
  enum_values.map { |v| v.is_a?(Hash) ? (v["value"] || v[:value]).to_s : v.to_s }
end

#external?Boolean

Returns:

  • (Boolean)


79
80
81
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 79

def external?
  source == "external" || source == :external
end

#lcp_managed?Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 63

def lcp_managed?
  @lcp_managed
end

#resolved_base_typeObject



111
112
113
114
115
116
117
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 111

def resolved_base_type
  if type_definition
    type_definition.base_type
  else
    type
  end
end

#resolved_label(model_name: nil) ⇒ Object

Priority: lcp_ruby.models.<model>.fields.<name> > lcp_ruby.fields.<name> > YAML ‘label:` > humanized name.



121
122
123
124
125
126
127
128
129
130
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 121

def resolved_label(model_name: nil)
  if model_name.present?
    result = I18n.t("lcp_ruby.models.#{model_name}.fields.#{name}", default: nil)
    return result if result
  end
  result = I18n.t("lcp_ruby.fields.#{name}", default: nil)
  return result if result

  @label
end

#sequence?Boolean

Returns:

  • (Boolean)


71
72
73
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 71

def sequence?
  !!@sequence
end

#service_accessor?Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 83

def service_accessor?
  source.is_a?(Hash) && source.key?("service")
end

#virtual?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/lcp_ruby/metadata/field_definition.rb', line 75

def virtual?
  source.present?
end