tina4ruby 3.13.17 → 3.13.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 198d9905bf51e280f45f2bba90aac40fd64ea1bdf0c0f0b29e9a80d5e95020c9
4
- data.tar.gz: 74c01ef1ac870c47aebf57e686a9b3bd7efa46f5c56c1d78df4c378102ee39f2
3
+ metadata.gz: 0073552dcac0e437fa36de2038f6958cbdbcde9077ec2427d9fd1bf77242da0e
4
+ data.tar.gz: c5c667382a67031bef1d7f3646020984942079edb5de9c5084c135ce4be68e9d
5
5
  SHA512:
6
- metadata.gz: 03a840227106a3e2c12a78bde6c5d62ff8e4eb3041bc443fe73cad5e5d6d1dbd366ffa5458d34faeffe8448ad8fb19ce9bd74c821a4d3ec436ab80aa984b58fc
7
- data.tar.gz: deefa98487ff855b8ad66beaa13b2e70f2b9f71677c0e317b52fc9153f43782a40723dc5519e814a2d65a29685fae18647f0bc84c124763aa8e5e7dcbddd07ca
6
+ metadata.gz: d7e9036bfe01826691e30382e35b8c4f70dfe2043602f41abae7a0e573993992a99f89e733b2b7dd74e4c2c2d6fe1c6be7faeb4d57d132d0be6c1d471f538afb
7
+ data.tar.gz: 7a4ec3bdd62b40c973e2fadbd52f205d92bc6fd2f0e18c1407a164a6cb27fcb03bffb50ec789851ac567105c1da81c6fbdcd00ece6fdbefef2411d1067f55610
@@ -84,7 +84,12 @@ module Tina4
84
84
  # Automatically:
85
85
  # - Registers an integer field for the column
86
86
  # - Calls belongs_to on this class (strip _id suffix for association name)
87
- # - Calls has_many on the referenced class (if already loaded)
87
+ # - Calls has_many on the referenced class. The accessor name is the
88
+ # declaring class name lowercased + "s" (e.g. Post → posts), matching
89
+ # Python; override with related_name:. Works whether the referenced
90
+ # class loaded before OR after this one, including the string form
91
+ # (references: "Author") for forward references — resolution is
92
+ # deferred via Tina4::ORM.inherited until the target class exists.
88
93
  #
89
94
  # @param name [Symbol] Column name (e.g. :user_id)
90
95
  # @param references [Class, String] Referenced model class or its name
@@ -122,12 +127,45 @@ module Tina4
122
127
  has_many_name: hm_key.to_sym,
123
128
  foreign_key: name.to_s
124
129
  }
130
+
131
+ # If the referenced model is ALREADY loaded (string form whose target
132
+ # is defined, or any forward reference that has since resolved), wire
133
+ # the deferred entry right now. The inherited hook on Tina4::ORM only
134
+ # fires when a NEW class is defined, so a string reference to a class
135
+ # that loaded BEFORE this one would otherwise never wire its has_many
136
+ # side. resolve_referenced_class returns the live class for either the
137
+ # Class or the string form.
138
+ resolved = resolve_referenced_class(references)
139
+ resolved.apply_fk_registry! if resolved && resolved.respond_to?(:apply_fk_registry!, true)
140
+ end
141
+
142
+ # Resolve a ForeignKeyField `references:` argument to a live Tina4::ORM
143
+ # subclass, or nil if it is not (yet) loaded. Accepts either a Class or a
144
+ # class-name String (with or without a namespace). The string form is the
145
+ # documented deferred-safe path: a bare constant used before its class is
146
+ # defined raises NameError (plain Ruby), so forward references must be
147
+ # written as strings.
148
+ def resolve_referenced_class(references)
149
+ return references if references.is_a?(Class)
150
+ return nil unless defined?(Tina4::ORM) && Tina4::ORM.respond_to?(:model_subclasses)
151
+
152
+ simple = references.to_s.split("::").last
153
+ Tina4::ORM.model_subclasses.find do |klass|
154
+ klass.name && klass.name.split("::").last == simple
155
+ end
156
+ rescue StandardError
157
+ nil
125
158
  end
126
159
 
127
160
  # Apply any deferred FK-registry has_many wiring for this class.
128
161
  # Called automatically when a class that is referenced by a ForeignKeyField is defined.
129
162
  def apply_fk_registry!
130
- class_simple_name = self.name.split("::").last
163
+ # Anonymous classes (Class.new(Tina4::ORM), common in specs) have a nil
164
+ # name and can never be a string-form ForeignKeyField target, so there
165
+ # is nothing to wire — bail out instead of raising on nil.split.
166
+ return if name.nil?
167
+
168
+ class_simple_name = name.split("::").last
131
169
  return unless defined?(@@_fk_registry) && @@_fk_registry.key?(class_simple_name)
132
170
 
133
171
  @@_fk_registry[class_simple_name].each do |entry|
data/lib/tina4/orm.rb CHANGED
@@ -16,6 +16,29 @@ module Tina4
16
16
  class ORM
17
17
  include Tina4::FieldTypes
18
18
 
19
+ # When a new model class is defined, resolve any deferred ForeignKeyField
20
+ # wiring that targets it. The string / forward-reference form of
21
+ # `foreign_key_field` (e.g. `references: "Author"`) records the has_many
22
+ # side in @@_fk_registry but cannot wire it until the referenced class
23
+ # actually loads — which is now. Without this hook apply_fk_registry! was
24
+ # never called, so the has_many side silently never wired. The class body
25
+ # (where the model's own foreign_key_field declarations run, populating the
26
+ # registry) executes AFTER inherited returns, so entries keyed on THIS
27
+ # class were already recorded by earlier-loaded models. Chain through super
28
+ # so we never clobber a future inherited hook.
29
+ def self.inherited(subclass)
30
+ super
31
+ (@_model_subclasses ||= []) << subclass
32
+ subclass.apply_fk_registry! if subclass.respond_to?(:apply_fk_registry!, true)
33
+ end
34
+
35
+ # Every Tina4::ORM subclass that has been loaded, in definition order.
36
+ # Mirrors Python's ORM.__subclasses__() — used to resolve string-form
37
+ # ForeignKeyField references to a live class.
38
+ def self.model_subclasses
39
+ @_model_subclasses ||= []
40
+ end
41
+
19
42
  class << self
20
43
  def db
21
44
  # v3.13.12: implicit binding from TINA4_DATABASE_URL.
@@ -132,7 +155,7 @@ module Tina4
132
155
  #
133
156
  # @return [Tina4::QueryBuilder]
134
157
  def query
135
- QueryBuilder.from(table_name, db: db)
158
+ QueryBuilder.from_table(table_name, db: db)
136
159
  end
137
160
 
138
161
  def find(id_or_filter = nil, filter = nil, **kwargs)
data/lib/tina4/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tina4
4
- VERSION = "3.13.17"
4
+ VERSION = "3.13.18"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tina4ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.13.17
4
+ version: 3.13.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina4 Team