Class: LcpRuby::Metadata::ModelDefinition
- Inherits:
-
Object
- Object
- LcpRuby::Metadata::ModelDefinition
- Defined in:
- lib/lcp_ruby/metadata/model_definition.rb
Instance Attribute Summary collapse
-
#abstract ⇒ Object
readonly
Returns the value of attribute abstract.
-
#associations ⇒ Object
readonly
Returns the value of attribute associations.
-
#bind_to ⇒ Object
readonly
Returns the value of attribute bind_to.
-
#bind_to_apply ⇒ Object
readonly
Returns the value of attribute bind_to_apply.
-
#data_source_config ⇒ Object
readonly
Returns the value of attribute data_source_config.
-
#display_templates ⇒ Object
readonly
Returns the value of attribute display_templates.
-
#events ⇒ Object
readonly
Returns the value of attribute events.
-
#fields ⇒ Object
readonly
Returns the value of attribute fields.
-
#indexes ⇒ Object
readonly
Returns the value of attribute indexes.
-
#inherits ⇒ Object
readonly
Returns the value of attribute inherits.
-
#label ⇒ Object
readonly
Returns the value of attribute label.
-
#label_plural ⇒ Object
readonly
Returns the value of attribute label_plural.
-
#label_plural_source_loc ⇒ Object
readonly
Returns the value of attribute label_plural_source_loc.
-
#label_source_loc ⇒ Object
readonly
Returns the value of attribute label_source_loc.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#positioning_config ⇒ Object
Returns the value of attribute positioning_config.
-
#raw_hash ⇒ Object
readonly
Returns the value of attribute raw_hash.
-
#scopes ⇒ Object
readonly
Returns the value of attribute scopes.
-
#slug_field ⇒ Object
readonly
Returns the value of attribute slug_field.
-
#source_path ⇒ Object
Returns the value of attribute source_path.
-
#source_type ⇒ Object
Returns the value of attribute source_type.
-
#sti_child ⇒ Object
readonly
Returns the value of attribute sti_child.
-
#table_name ⇒ Object
Returns the value of attribute table_name.
-
#validations ⇒ Object
readonly
Returns the value of attribute validations.
-
#virtual_columns ⇒ Object
(also: #aggregates)
readonly
Returns the value of attribute virtual_columns.
Class Method Summary collapse
- .from_hash(hash) ⇒ Object
- .parse_associations(associations_data, owner_name = nil) ⇒ Object
- .parse_display_templates(data) ⇒ Object
- .parse_events(events_data) ⇒ Object
- .parse_fields(fields_data) ⇒ Object
- .parse_indexes(data) ⇒ Object
- .parse_validations(validations_data) ⇒ Object
- .parse_vc_hash(data, result) ⇒ Object
-
.parse_virtual_columns(hash) ⇒ Object
Parse both “aggregates” and “virtual_columns” keys, merge, and error on collision.
Instance Method Summary collapse
- #abstract? ⇒ Boolean
-
#api_model? ⇒ Boolean
Returns true if this model is backed by an external data source (REST API, host adapter).
- #auditing? ⇒ Boolean
- #auditing_options ⇒ Object
-
#belongs_to_fk_map ⇒ Object
Returns a Hash mapping FK field name to its belongs_to AssociationDefinition.
-
#bind_to? ⇒ Boolean
Returns true if this model binds to an existing ActiveRecord class in the host app.
-
#bind_to_auto_features ⇒ Object
Bind-to applicator features that must run even if not listed in ‘bind_to_apply`, because the corresponding YAML-declared virtual fields are otherwise unreachable at runtime.
- #custom_fields_enabled? ⇒ Boolean
-
#data_source_type ⇒ Object
Returns the data source type as a symbol: :db, :rest_json, or :host.
-
#declared_macros ⇒ Object
Returns the macros this model declares, as an array of symbols.
-
#display_bind_to ⇒ Object
Normalized bind_to class name for display in error / warning / log messages: strips the leading “::” so output reads “LcpRuby::User” not “::LcpRuby::User”.
- #display_template(name = "default") ⇒ Object
-
#each_enum_value ⇒ Object
Yields per-enum-value labels.
-
#each_field ⇒ Object
Yields per-field label info for the i18n_check lint walker.
- #enum_fields ⇒ Object
- #field(name) ⇒ Object
-
#find_belongs_to(name) ⇒ Object
Look up a belongs_to association by name.
- #has_index_for?(field_name) ⇒ Boolean
- #has_uniqueness_validation?(field_name) ⇒ Boolean
-
#initialize(attrs = {}) ⇒ ModelDefinition
constructor
A new instance of ModelDefinition.
- #label_method ⇒ Object
-
#managed_fk_columns ⇒ Object
Required column names for every ‘lcp_managed: true` belongs_to on this model.
- #parameterized_scope(name) ⇒ Object
- #parameterized_scopes ⇒ Object
- #positioned? ⇒ Boolean
- #positioning_field ⇒ Object
- #positioning_scope ⇒ Object
-
#primary_key_column ⇒ Object
Neutral primary-key column accessor.
-
#primary_key_type ⇒ Object
Neutral primary-key type accessor.
-
#resolved_label ⇒ Object
Returns the singular model label resolved via i18n.
-
#scope_names ⇒ Object
Returns the names of named scopes declared in the YAML ‘scopes:` block as Strings.
- #soft_delete? ⇒ Boolean
- #soft_delete_column ⇒ Object
- #soft_delete_options ⇒ Object
-
#source_location_for(attribute) ⇒ Object
i18n_check Phase 3a façade — returns ‘{ “file” => …, “line” => N }` for the DSL line that set this attribute, or nil when the model was loaded from YAML (or the attribute was not set at all).
- #sti_child? ⇒ Boolean
- #sti_parent? ⇒ Boolean
-
#sti_parent_name ⇒ Object
Returns the STI parent model name, or nil if not an STI child.
-
#supported_filter_operators ⇒ Object
Returns supported filter operators for this model’s data source.
- #timestamps? ⇒ Boolean
- #tree? ⇒ Boolean
- #tree_children_name ⇒ Object
- #tree_dependent ⇒ Object
- #tree_max_depth ⇒ Object
- #tree_options ⇒ Object
- #tree_ordered? ⇒ Boolean
- #tree_parent_field ⇒ Object
- #tree_parent_name ⇒ Object
- #tree_position_field ⇒ Object
- #userstamp_column_names ⇒ Object
- #userstamps? ⇒ Boolean
- #userstamps_creator_association_name ⇒ Object
- #userstamps_creator_field ⇒ Object
- #userstamps_creator_name_field ⇒ Object
- #userstamps_options ⇒ Object
- #userstamps_store_name? ⇒ Boolean
- #userstamps_updater_association_name ⇒ Object
- #userstamps_updater_field ⇒ Object
- #userstamps_updater_name_field ⇒ Object
- #virtual? ⇒ Boolean
- #virtual_column(name) ⇒ Object (also: #aggregate)
- #virtual_column_names ⇒ Object (also: #aggregate_names)
-
#workflow ⇒ Object
Returns the registered workflow object for this model, or nil if no workflow is declared (or Workflow::Registry isn’t available yet).
-
#workflow? ⇒ Boolean
Predicate paralleling auditing?, tree?, positioned?, soft_delete? — true when this model declares a workflow (via Workflow::Registry, populated at engine boot from any of the three sources: YAML/DSL, DB, host adapter).
Constructor Details
#initialize(attrs = {}) ⇒ ModelDefinition
Returns a new instance of ModelDefinition.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 16 def initialize(attrs = {}) @name = attrs[:name].to_s @label = attrs[:label] || @name.humanize @label_plural = attrs[:label_plural] || @label.pluralize @table_name = attrs[:table_name] || @name.pluralize @fields = attrs[:fields] || [] @validations = attrs[:validations] || [] @associations = attrs[:associations] || [] @scopes = attrs[:scopes] || [] @events = attrs[:events] || [] @options = attrs[:options] || {} @display_templates = attrs[:display_templates] || {} @virtual_columns = attrs[:virtual_columns] || attrs[:aggregates] || {} @indexes = attrs[:indexes] || [] @positioning_config = attrs[:positioning_config] @data_source_config = attrs[:data_source_config] @raw_hash = attrs[:raw_hash] @source_path = attrs[:source_path] @source_type = attrs[:source_type] @abstract = attrs.fetch(:abstract, false) @inherits = attrs[:inherits] @sti_child = attrs.fetch(:sti_child, false) @bind_to = attrs[:bind_to] @bind_to_apply = attrs[:bind_to_apply] || [] @slug_field = attrs[:slug_field]&.to_s.presence # i18n_check Phase 3a façade source-location capture. Set by # ModelBuilder; nil for YAML-loaded models (Pass 3 covers YAML). @label_source_loc = attrs[:label_source_loc] @label_plural_source_loc = attrs[:label_plural_source_loc] validate! end |
Instance Attribute Details
#abstract ⇒ Object (readonly)
Returns the value of attribute abstract.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def abstract @abstract end |
#associations ⇒ Object (readonly)
Returns the value of attribute associations.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def associations @associations end |
#bind_to ⇒ Object (readonly)
Returns the value of attribute bind_to.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def bind_to @bind_to end |
#bind_to_apply ⇒ Object (readonly)
Returns the value of attribute bind_to_apply.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def bind_to_apply @bind_to_apply end |
#data_source_config ⇒ Object (readonly)
Returns the value of attribute data_source_config.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def data_source_config @data_source_config end |
#display_templates ⇒ Object (readonly)
Returns the value of attribute display_templates.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def display_templates @display_templates end |
#events ⇒ Object (readonly)
Returns the value of attribute events.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def events @events end |
#fields ⇒ Object (readonly)
Returns the value of attribute fields.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def fields @fields end |
#indexes ⇒ Object (readonly)
Returns the value of attribute indexes.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def indexes @indexes end |
#inherits ⇒ Object (readonly)
Returns the value of attribute inherits.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def inherits @inherits end |
#label ⇒ Object (readonly)
Returns the value of attribute label.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def label @label end |
#label_plural ⇒ Object (readonly)
Returns the value of attribute label_plural.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def label_plural @label_plural end |
#label_plural_source_loc ⇒ Object (readonly)
Returns the value of attribute label_plural_source_loc.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def label_plural_source_loc @label_plural_source_loc end |
#label_source_loc ⇒ Object (readonly)
Returns the value of attribute label_source_loc.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def label_source_loc @label_source_loc end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def name @name end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def @options end |
#positioning_config ⇒ Object
Returns the value of attribute positioning_config.
11 12 13 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 11 def positioning_config @positioning_config end |
#raw_hash ⇒ Object (readonly)
Returns the value of attribute raw_hash.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def raw_hash @raw_hash end |
#scopes ⇒ Object (readonly)
Returns the value of attribute scopes.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def scopes @scopes end |
#slug_field ⇒ Object (readonly)
Returns the value of attribute slug_field.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def slug_field @slug_field end |
#source_path ⇒ Object
Returns the value of attribute source_path.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def source_path @source_path end |
#source_type ⇒ Object
Returns the value of attribute source_type.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def source_type @source_type end |
#sti_child ⇒ Object (readonly)
Returns the value of attribute sti_child.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def sti_child @sti_child end |
#table_name ⇒ Object
Returns the value of attribute table_name.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def table_name @table_name end |
#validations ⇒ Object (readonly)
Returns the value of attribute validations.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def validations @validations end |
#virtual_columns ⇒ Object (readonly) Also known as: aggregates
Returns the value of attribute virtual_columns.
4 5 6 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 4 def virtual_columns @virtual_columns end |
Class Method Details
.from_hash(hash) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 49 def self.from_hash(hash) new( name: hash["name"], label: hash["label"], label_plural: hash["label_plural"], table_name: hash["table_name"], fields: parse_fields(hash["fields"]), validations: parse_validations(hash["validations"]), associations: parse_associations(hash["associations"], hash["name"]), scopes: (hash["scopes"] || []).map { |s| HashUtils.stringify_deep(s) }, events: parse_events(hash["events"]), options: hash["options"] || {}, display_templates: parse_display_templates(hash["display_templates"]), virtual_columns: parse_virtual_columns(hash), indexes: parse_indexes(hash["indexes"]), positioning_config: normalize_positioning(hash["positioning"]), data_source_config: hash["data_source"], raw_hash: hash, abstract: hash["abstract"] == true, inherits: hash["inherits"], sti_child: hash[ModelInheritanceResolver::STI_CHILD_KEY] == true, bind_to: hash["bind_to"], bind_to_apply: hash["bind_to_apply"], slug_field: hash["slug_field"], label_source_loc: hash["_label_source_loc"], label_plural_source_loc: hash["_label_plural_source_loc"] ) end |
.parse_associations(associations_data, owner_name = nil) ⇒ Object
565 566 567 568 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 565 def self.parse_associations(associations_data, owner_name = nil) return [] unless associations_data.is_a?(Array) associations_data.map { |a| AssociationDefinition.from_hash(a, owner_name) } end |
.parse_display_templates(data) ⇒ Object
599 600 601 602 603 604 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 599 def self.parse_display_templates(data) return {} unless data.is_a?(Hash) data.each_with_object({}) do |(name, hash), result| result[name.to_s] = DisplayTemplateDefinition.from_hash(name, hash) end end |
.parse_events(events_data) ⇒ Object
570 571 572 573 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 570 def self.parse_events(events_data) return [] unless events_data.is_a?(Array) events_data.map { |e| EventDefinition.from_hash(e) } end |
.parse_fields(fields_data) ⇒ Object
555 556 557 558 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 555 def self.parse_fields(fields_data) return [] unless fields_data.is_a?(Array) fields_data.map { |f| FieldDefinition.from_hash(f) } end |
.parse_indexes(data) ⇒ Object
606 607 608 609 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 606 def self.parse_indexes(data) return [] unless data.is_a?(Array) data.map { |idx| HashUtils.stringify_deep(idx) } end |
.parse_validations(validations_data) ⇒ Object
560 561 562 563 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 560 def self.parse_validations(validations_data) return [] unless validations_data.is_a?(Array) validations_data.map { |v| ValidationDefinition.new(v) } end |
.parse_vc_hash(data, result) ⇒ Object
593 594 595 596 597 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 593 def self.parse_vc_hash(data, result) data.each do |name, hash| result[name.to_s] = VirtualColumnDefinition.from_hash(name, hash) end end |
.parse_virtual_columns(hash) ⇒ Object
Parse both “aggregates” and “virtual_columns” keys, merge, and error on collision.
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 576 def self.parse_virtual_columns(hash) agg_data = hash["aggregates"] || {} vc_data = hash["virtual_columns"] || {} if agg_data.is_a?(Hash) && vc_data.is_a?(Hash) collisions = agg_data.keys.map(&:to_s) & vc_data.keys.map(&:to_s) if collisions.any? raise MetadataError, "Model '#{hash['name']}': name collision between aggregates and virtual_columns: #{collisions.join(', ')}" end end merged = {} parse_vc_hash(agg_data, merged) if agg_data.is_a?(Hash) parse_vc_hash(vc_data, merged) if vc_data.is_a?(Hash) merged end |
Instance Method Details
#abstract? ⇒ Boolean
148 149 150 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 148 def abstract? @abstract == true end |
#api_model? ⇒ Boolean
Returns true if this model is backed by an external data source (REST API, host adapter).
193 194 195 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 193 def api_model? @data_source_config.is_a?(Hash) && @data_source_config["type"].present? end |
#auditing? ⇒ Boolean
228 229 230 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 228 def auditing? boolean_or_hash_option("auditing").first end |
#auditing_options ⇒ Object
232 233 234 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 232 def boolean_or_hash_option("auditing").last end |
#belongs_to_fk_map ⇒ Object
Returns a Hash mapping FK field name to its belongs_to AssociationDefinition. e.g. { “company_id” => <AssociationDefinition name=“company”> } Memoized since it’s called from multiple places (ColumnSet, DependencyCollector, PermissionEvaluator). Includes tree-generated parent association when tree? is enabled.
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 460 def belongs_to_fk_map @belongs_to_fk_map ||= begin map = associations .select { |a| a.type == "belongs_to" && a.foreign_key.present? } .each_with_object({}) { |a, h| h[a.foreign_key] = a } # Add tree-generated parent association if not already present if tree? && !map.key?(tree_parent_field) map[tree_parent_field] = AssociationDefinition.new( type: "belongs_to", name: tree_parent_name, target_model: name, foreign_key: tree_parent_field, required: false ) end map end end |
#bind_to? ⇒ Boolean
Returns true if this model binds to an existing ActiveRecord class in the host app.
170 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 170 def bind_to? = bind_to.present? |
#bind_to_auto_features ⇒ Object
Bind-to applicator features that must run even if not listed in ‘bind_to_apply`, because the corresponding YAML-declared virtual fields are otherwise unreachable at runtime.
367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 367 def bind_to_auto_features features = [] features << "enums" if enum_fields.any?(&:virtual?) features << "service_accessors" if fields.any?(&:service_accessor?) # Auto-enable defaults so bind_to models get the same default-on-create # semantics as dynamic LCP models. Without this, fields like # `theme: enum, default: auto, source: json_field` on a bind_to model # never get the after_initialize callback that writes the default into # the underlying store — host.create! leaves the JSON key absent. features << "defaults" if fields.any? { |f| !f.default.nil? } features end |
#custom_fields_enabled? ⇒ Boolean
144 145 146 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 144 def custom_fields_enabled? .fetch("custom_fields", false) == true end |
#data_source_type ⇒ Object
Returns the data source type as a symbol: :db, :rest_json, or :host.
198 199 200 201 202 203 204 205 206 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 198 def data_source_type return :db unless api_model? case @data_source_config["type"] when "rest_json" then :rest_json when "host" then :host else :db end end |
#declared_macros ⇒ Object
Returns the macros this model declares, as an array of symbols. Consumed by Metadata::ReservedNames.reserved_clashes_for_macro to iterate macro-specific reserved-name lookups, and by future Phase 3 ConfigurationValidator passes that need a single source of truth for “which macros does this model declare.” Memoized.
435 436 437 438 439 440 441 442 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 435 def declared_macros @declared_macros ||= [].tap do |m| m << :auditing if auditing? m << :tree if tree? m << :positioning if positioned? m << :workflow if workflow? end end |
#display_bind_to ⇒ Object
Normalized bind_to class name for display in error / warning / log messages: strips the leading “::” so output reads “LcpRuby::User” not “::LcpRuby::User”. Returns nil for non-bind_to models.
175 176 177 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 175 def display_bind_to bind_to&.to_s&.delete_prefix("::") end |
#display_template(name = "default") ⇒ Object
380 381 382 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 380 def display_template(name = "default") display_templates[name.to_s] end |
#each_enum_value ⇒ Object
Yields per-enum-value labels. The source location is the enclosing field declaration (‘field :status, :enum, values: { … }`), not the specific value entry — see spec §I “Special case: enum value labels”. Pass 2 (AST) catches the precise value pair.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 116 def each_enum_value return enum_for(:each_enum_value) unless block_given? fields.each do |field| next unless field.enum? field.enum_values.each do |entry| next unless entry.is_a?(Hash) value = entry["value"] || entry[:value] next if value.nil? label = entry["label"] || entry[:label] source = entry["_label_source_loc"] || entry[:_label_source_loc] yield(label: label, field: field.name, value: value, source: source) end end end |
#each_field ⇒ Object
Yields per-field label info for the i18n_check lint walker. Includes EVERY field — author-set explicit labels and humanize fallbacks alike. The walker uses the missing-translation check to decide whether to flag (a humanize-fallback field with no locale entry is still broken UX in non-default locales). Source is nil for fields without an explicit DSL ‘label:`.
96 97 98 99 100 101 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 96 def each_field return enum_for(:each_field) unless block_given? fields.each do |field| yield(label: field.label, field: field.name, source: field.label_source_loc) end end |
#enum_fields ⇒ Object
360 361 362 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 360 def enum_fields fields.select(&:enum?) end |
#field(name) ⇒ Object
325 326 327 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 325 def field(name) fields.find { |f| f.name == name.to_s } end |
#find_belongs_to(name) ⇒ Object
Look up a belongs_to association by name. Returns nil when the name doesn’t match or matches a non-belongs_to (has_many, has_one, polymorphic through) association.
332 333 334 335 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 332 def find_belongs_to(name) assoc = associations.find { |a| a.name == name.to_s } assoc if assoc&.belongs_to? end |
#has_index_for?(field_name) ⇒ Boolean
344 345 346 347 348 349 350 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 344 def has_index_for?(field_name) name = field_name.to_s indexes.any? { |idx| cols = Array(idx["columns"] || idx["column"]) cols.include?(name) } end |
#has_uniqueness_validation?(field_name) ⇒ Boolean
337 338 339 340 341 342 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 337 def has_uniqueness_validation?(field_name) name = field_name.to_s f = field(name) (f && f.validations.any? { |v| v.type == "uniqueness" }) || validations.any? { |v| v.type == "uniqueness" && v.target_field == name } end |
#label_method ⇒ Object
140 141 142 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 140 def label_method ["label_method"] || "to_s" end |
#managed_fk_columns ⇒ Object
Required column names for every ‘lcp_managed: true` belongs_to on this model. Polymorphic associations contribute both `<name>_id` and `<name>_type`; non-polymorphic contribute just the FK column. Used by SchemaManager (which columns to add) and Engine (the auto_migrate=false escape hatch). Memoized — ModelDefinition is immutable after initialize, same invariant `belongs_to_fk_map` already relies on.
186 187 188 189 190 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 186 def managed_fk_columns @managed_fk_columns ||= associations .select { |a| a.belongs_to? && a.lcp_managed? } .flat_map { |a| a.polymorphic ? [ a.foreign_key, "#{a.name}_type" ] : [ a.foreign_key ] } end |
#parameterized_scope(name) ⇒ Object
356 357 358 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 356 def parameterized_scope(name) parameterized_scopes.find { |s| s["name"] == name.to_s } end |
#parameterized_scopes ⇒ Object
352 353 354 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 352 def parameterized_scopes scopes.select { |s| s["type"] == "parameterized" } end |
#positioned? ⇒ Boolean
396 397 398 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 396 def positioned? @positioning_config.present? end |
#positioning_field ⇒ Object
400 401 402 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 400 def positioning_field positioning_config&.fetch("field", "position") || "position" end |
#positioning_scope ⇒ Object
404 405 406 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 404 def positioning_scope Array(positioning_config&.fetch("scope", nil)).compact end |
#primary_key_column ⇒ Object
Neutral primary-key column accessor. Defaults to “id” to match Rails. Overridden by custom_primary_key.md Tier 2 when/if that spec lands.
446 447 448 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 446 def primary_key_column "id" end |
#primary_key_type ⇒ Object
Neutral primary-key type accessor. Defaults to :bigint to match Rails. Overridden by custom_primary_key.md Tier 1 when/if that spec lands.
452 453 454 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 452 def primary_key_type :bigint end |
#resolved_label ⇒ Object
Returns the singular model label resolved via i18n.
132 133 134 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 132 def resolved_label I18n.t("lcp_ruby.models.#{name}.one", default: @label) end |
#scope_names ⇒ Object
Returns the names of named scopes declared in the YAML ‘scopes:` block as Strings. Scopes are stored as String-keyed Hashes after `HashUtils.stringify_deep` (see `from_hash`), so the right accessor is `s`. Falls back to Symbol key, then to the entry’s ‘to_s` for legacy bare-symbol forms.
108 109 110 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 108 def scope_names scopes.map { |s| s.is_a?(Hash) ? (s["name"] || s[:name]).to_s : s.to_s } end |
#soft_delete? ⇒ Boolean
216 217 218 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 216 def soft_delete? boolean_or_hash_option("soft_delete").first end |
#soft_delete_column ⇒ Object
224 225 226 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 224 def soft_delete_column .fetch("column", "discarded_at") end |
#soft_delete_options ⇒ Object
220 221 222 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 220 def boolean_or_hash_option("soft_delete").last end |
#source_location_for(attribute) ⇒ Object
i18n_check Phase 3a façade — returns ‘{ “file” => …, “line” => N }` for the DSL line that set this attribute, or nil when the model was loaded from YAML (or the attribute was not set at all). See `docs/design/i18n_consistency_check.md` §B “Façade method signatures”.
83 84 85 86 87 88 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 83 def source_location_for(attribute) case attribute when :label then @label_source_loc when :label_plural then @label_plural_source_loc end end |
#sti_child? ⇒ Boolean
156 157 158 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 156 def sti_child? @sti_child == true end |
#sti_parent? ⇒ Boolean
152 153 154 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 152 def sti_parent? .fetch("sti", false) == true && !sti_child? end |
#sti_parent_name ⇒ Object
Returns the STI parent model name, or nil if not an STI child.
161 162 163 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 161 def sti_parent_name @inherits if sti_child? end |
#supported_filter_operators ⇒ Object
Returns supported filter operators for this model’s data source. Falls back to a standard set for DB models.
210 211 212 213 214 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 210 def supported_filter_operators return nil unless api_model? @data_source_config["supported_operators"] end |
#timestamps? ⇒ Boolean
136 137 138 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 136 def .fetch("timestamps", true) end |
#tree? ⇒ Boolean
289 290 291 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 289 def tree? boolean_or_hash_option("tree").first end |
#tree_children_name ⇒ Object
301 302 303 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 301 def tree_children_name .fetch("children_name", "children") end |
#tree_dependent ⇒ Object
309 310 311 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 309 def tree_dependent .fetch("dependent", "destroy") end |
#tree_max_depth ⇒ Object
313 314 315 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 313 def tree_max_depth .fetch("max_depth", 10) end |
#tree_options ⇒ Object
293 294 295 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 293 def @tree_options ||= boolean_or_hash_option("tree").last end |
#tree_ordered? ⇒ Boolean
317 318 319 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 317 def tree_ordered? .fetch("ordered", false) == true end |
#tree_parent_field ⇒ Object
297 298 299 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 297 def tree_parent_field .fetch("parent_field", "parent_id") end |
#tree_parent_name ⇒ Object
305 306 307 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 305 def tree_parent_name .fetch("parent_name", "parent") end |
#tree_position_field ⇒ Object
321 322 323 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 321 def tree_position_field .fetch("position_field", "position") end |
#userstamp_column_names ⇒ Object
278 279 280 281 282 283 284 285 286 287 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 278 def userstamp_column_names return [] unless userstamps? cols = [ userstamps_creator_field, userstamps_updater_field ] if userstamps_store_name? cols << userstamps_creator_name_field cols << userstamps_updater_name_field end cols end |
#userstamps? ⇒ Boolean
236 237 238 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 236 def userstamps? boolean_or_hash_option("userstamps").first end |
#userstamps_creator_association_name ⇒ Object
256 257 258 259 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 256 def userstamps_creator_association_name .fetch("created_by_association", strip_id_suffix(userstamps_creator_field)) end |
#userstamps_creator_field ⇒ Object
244 245 246 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 244 def userstamps_creator_field .fetch("created_by", "created_by_id") end |
#userstamps_creator_name_field ⇒ Object
266 267 268 269 270 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 266 def userstamps_creator_name_field return nil unless userstamps_store_name? .fetch("created_by_name_field", "#{strip_id_suffix(userstamps_creator_field)}_name") end |
#userstamps_options ⇒ Object
240 241 242 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 240 def boolean_or_hash_option("userstamps").last end |
#userstamps_store_name? ⇒ Boolean
252 253 254 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 252 def userstamps_store_name? .fetch("store_name", false) == true end |
#userstamps_updater_association_name ⇒ Object
261 262 263 264 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 261 def userstamps_updater_association_name .fetch("updated_by_association", strip_id_suffix(userstamps_updater_field)) end |
#userstamps_updater_field ⇒ Object
248 249 250 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 248 def userstamps_updater_field .fetch("updated_by", "updated_by_id") end |
#userstamps_updater_name_field ⇒ Object
272 273 274 275 276 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 272 def userstamps_updater_name_field return nil unless userstamps_store_name? .fetch("updated_by_name_field", "#{strip_id_suffix(userstamps_updater_field)}_name") end |
#virtual? ⇒ Boolean
165 166 167 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 165 def virtual? table_name == "_virtual" end |
#virtual_column(name) ⇒ Object Also known as: aggregate
384 385 386 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 384 def virtual_column(name) virtual_columns[name.to_s] end |
#virtual_column_names ⇒ Object Also known as: aggregate_names
388 389 390 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 388 def virtual_column_names virtual_columns.keys end |
#workflow ⇒ Object
Returns the registered workflow object for this model, or nil if no workflow is declared (or Workflow::Registry isn’t available yet). Memoized. Side-benefit: collapses the duplicated workflow_for_model memoizers in presenter/action_set.rb and presenter/layout_builder.rb to a single call site (deferred to follow-up PR).
422 423 424 425 426 427 428 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 422 def workflow return @workflow if defined?(@workflow) @workflow = if LcpRuby::Workflow::Registry.available? LcpRuby::Workflow::Registry.workflow_for_model(name) end end |
#workflow? ⇒ Boolean
Predicate paralleling auditing?, tree?, positioned?, soft_delete? — true when this model declares a workflow (via Workflow::Registry, populated at engine boot from any of the three sources: YAML/DSL, DB, host adapter). Requires Workflow::Registry to be ‘available?` (Setup.apply! has run); see lib/tasks/lcp_ruby.rake which invokes Setup.apply! before validation.
413 414 415 |
# File 'lib/lcp_ruby/metadata/model_definition.rb', line 413 def workflow? !workflow.nil? end |