Module: Tina4::FieldTypes::ClassMethods
- Defined in:
- lib/tina4/field_types.rb
Instance Method Summary collapse
-
#apply_fk_registry! ⇒ Object
Apply any deferred FK-registry has_many wiring for this class.
- #blob_field(name, nullable: true, default: nil) ⇒ Object
- #boolean_field(name, nullable: true, default: nil) ⇒ Object
- #date_field(name, nullable: true, default: nil) ⇒ Object
- #datetime_field(name, nullable: true, default: nil) ⇒ Object
- #decimal_field(name, precision: 10, scale: 2, nullable: true, default: nil) ⇒ Object
- #field_definitions ⇒ Object
- #float_field(name, nullable: true, default: nil) ⇒ Object
-
#foreign_key_field(name, references:, related_name: nil, **options) ⇒ Object
Declare a foreign key integer column and auto-wire relationships.
- #integer_field(name, primary_key: false, auto_increment: false, nullable: true, default: nil) ⇒ Object
- #json_field(name, nullable: true, default: nil) ⇒ Object
- #numeric_field(name, nullable: true, default: nil) ⇒ Object
- #primary_key_field ⇒ Object
-
#resolve_referenced_class(references) ⇒ Object
Resolve a ForeignKeyField ‘references:` argument to a live Tina4::ORM subclass, or nil if it is not (yet) loaded.
- #string_field(name, length: 255, primary_key: false, nullable: true, default: nil) ⇒ Object
- #table_name(name = nil) ⇒ Object
- #text_field(name, nullable: true, default: nil) ⇒ Object
- #timestamp_field(name, nullable: true, default: nil) ⇒ Object
Instance Method Details
#apply_fk_registry! ⇒ Object
Apply any deferred FK-registry has_many wiring for this class. Called automatically when a class that is referenced by a ForeignKeyField is defined.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/tina4/field_types.rb', line 162 def apply_fk_registry! # Anonymous classes (Class.new(Tina4::ORM), common in specs) have a nil # name and can never be a string-form ForeignKeyField target, so there # is nothing to wire — bail out instead of raising on nil.split. return if name.nil? class_simple_name = name.split("::").last return unless defined?(@@_fk_registry) && @@_fk_registry.key?(class_simple_name) @@_fk_registry[class_simple_name].each do |entry| next if entry[:applied] has_many(entry[:has_many_name], class_name: entry[:declaring_class].name.split("::").last, foreign_key: entry[:foreign_key]) if respond_to?(:has_many, true) entry[:applied] = true end end |
#blob_field(name, nullable: true, default: nil) ⇒ Object
74 75 76 |
# File 'lib/tina4/field_types.rb', line 74 def blob_field(name, nullable: true, default: nil) register_field(name, :blob, nullable: nullable, default: default) end |
#boolean_field(name, nullable: true, default: nil) ⇒ Object
58 59 60 |
# File 'lib/tina4/field_types.rb', line 58 def boolean_field(name, nullable: true, default: nil) register_field(name, :boolean, nullable: nullable, default: default) end |
#date_field(name, nullable: true, default: nil) ⇒ Object
62 63 64 |
# File 'lib/tina4/field_types.rb', line 62 def date_field(name, nullable: true, default: nil) register_field(name, :date, nullable: nullable, default: default) end |
#datetime_field(name, nullable: true, default: nil) ⇒ Object
66 67 68 |
# File 'lib/tina4/field_types.rb', line 66 def datetime_field(name, nullable: true, default: nil) register_field(name, :datetime, nullable: nullable, default: default) end |
#decimal_field(name, precision: 10, scale: 2, nullable: true, default: nil) ⇒ Object
49 50 51 52 |
# File 'lib/tina4/field_types.rb', line 49 def decimal_field(name, precision: 10, scale: 2, nullable: true, default: nil) register_field(name, :decimal, precision: precision, scale: scale, nullable: nullable, default: default) end |
#field_definitions ⇒ Object
10 11 12 |
# File 'lib/tina4/field_types.rb', line 10 def field_definitions @field_definitions ||= {} end |
#float_field(name, nullable: true, default: nil) ⇒ Object
45 46 47 |
# File 'lib/tina4/field_types.rb', line 45 def float_field(name, nullable: true, default: nil) register_field(name, :float, nullable: nullable, default: default) end |
#foreign_key_field(name, references:, related_name: nil, **options) ⇒ Object
Declare a foreign key integer column and auto-wire relationships.
Automatically:
- Registers an integer field for the column
- Calls belongs_to on this class (strip _id suffix for association name)
- Calls has_many on the referenced class. The accessor name is the
declaring class name lowercased + "s" (e.g. Post → posts), matching
Python; override with related_name:. Works whether the referenced
class loaded before OR after this one, including the string form
(references: "Author") for forward references — resolution is
deferred via Tina4::ORM.inherited until the target class exists.
Example:
class Post < Tina4::ORM
integer_field :id, primary_key: true
foreign_key_field :user_id, references: User
end
# post.user → belongs_to auto-wired
# user.posts → has_many auto-wired
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 140 |
# File 'lib/tina4/field_types.rb', line 105 def foreign_key_field(name, references:, related_name: nil, **) register_field(name, :integer, **) # Derive association name: strip _id suffix belongs_name = name.to_s.end_with?("_id") ? name.to_s[0..-4].to_sym : name.to_sym # Wire belongs_to on this class belongs_to(belongs_name, class_name: references.to_s.split("::").last, foreign_key: name.to_s) if respond_to?(:belongs_to, true) # Wire has_many on referenced class (if already a loaded Class) if references.is_a?(Class) && references.respond_to?(:has_many, true) hm_name = ( || "#{self.name.split("::").last.downcase}s").to_sym references.has_many(hm_name, class_name: self.name.split("::").last, foreign_key: name.to_s) end # Register for deferred wiring (resolves when referenced class is later loaded) @@_fk_registry ||= {} ref_name = references.is_a?(Class) ? references.name.split("::").last : references.to_s.split("::").last @@_fk_registry[ref_name] ||= [] hm_key = ( || "#{self.name.split("::").last.downcase}s").to_s @@_fk_registry[ref_name] << { declaring_class: self, has_many_name: hm_key.to_sym, foreign_key: name.to_s } # If the referenced model is ALREADY loaded (string form whose target # is defined, or any forward reference that has since resolved), wire # the deferred entry right now. The inherited hook on Tina4::ORM only # fires when a NEW class is defined, so a string reference to a class # that loaded BEFORE this one would otherwise never wire its has_many # side. resolve_referenced_class returns the live class for either the # Class or the string form. resolved = resolve_referenced_class(references) resolved.apply_fk_registry! if resolved && resolved.respond_to?(:apply_fk_registry!, true) end |
#integer_field(name, primary_key: false, auto_increment: false, nullable: true, default: nil) ⇒ Object
31 32 33 34 |
# File 'lib/tina4/field_types.rb', line 31 def integer_field(name, primary_key: false, auto_increment: false, nullable: true, default: nil) register_field(name, :integer, primary_key: primary_key, auto_increment: auto_increment, nullable: nullable, default: default) end |
#json_field(name, nullable: true, default: nil) ⇒ Object
78 79 80 |
# File 'lib/tina4/field_types.rb', line 78 def json_field(name, nullable: true, default: nil) register_field(name, :json, nullable: nullable, default: default) end |
#numeric_field(name, nullable: true, default: nil) ⇒ Object
54 55 56 |
# File 'lib/tina4/field_types.rb', line 54 def numeric_field(name, nullable: true, default: nil) register_field(name, :float, nullable: nullable, default: default) end |
#primary_key_field ⇒ Object
14 15 16 |
# File 'lib/tina4/field_types.rb', line 14 def primary_key_field @primary_key_field end |
#resolve_referenced_class(references) ⇒ Object
Resolve a ForeignKeyField ‘references:` argument to a live Tina4::ORM subclass, or nil if it is not (yet) loaded. Accepts either a Class or a class-name String (with or without a namespace). The string form is the documented deferred-safe path: a bare constant used before its class is defined raises NameError (plain Ruby), so forward references must be written as strings.
148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/tina4/field_types.rb', line 148 def resolve_referenced_class(references) return references if references.is_a?(Class) return nil unless defined?(Tina4::ORM) && Tina4::ORM.respond_to?(:model_subclasses) simple = references.to_s.split("::").last Tina4::ORM.model_subclasses.find do |klass| klass.name && klass.name.split("::").last == simple end rescue StandardError nil end |
#string_field(name, length: 255, primary_key: false, nullable: true, default: nil) ⇒ Object
36 37 38 39 |
# File 'lib/tina4/field_types.rb', line 36 def string_field(name, length: 255, primary_key: false, nullable: true, default: nil) register_field(name, :string, length: length, primary_key: primary_key, nullable: nullable, default: default) end |
#table_name(name = nil) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/tina4/field_types.rb', line 18 def table_name(name = nil) if name @table_name = name else base = self.name.split("::").last.downcase # Pluralize by default (add "s") unless ORM_PLURAL_TABLE_NAMES is explicitly disabled unless ENV.fetch("TINA4_ORM_PLURAL_TABLE_NAMES", "").match?(/\A(false|0|no)\z/i) base += "s" unless base.end_with?("s") end @table_name || base end end |
#text_field(name, nullable: true, default: nil) ⇒ Object
41 42 43 |
# File 'lib/tina4/field_types.rb', line 41 def text_field(name, nullable: true, default: nil) register_field(name, :text, nullable: nullable, default: default) end |
#timestamp_field(name, nullable: true, default: nil) ⇒ Object
70 71 72 |
# File 'lib/tina4/field_types.rb', line 70 def (name, nullable: true, default: nil) register_field(name, :timestamp, nullable: nullable, default: default) end |