Class: ActiveFacts::Persistence::Column
- Inherits:
-
Object
- Object
- ActiveFacts::Persistence::Column
- Defined in:
- lib/activefacts/mapping/rails.rb,
lib/activefacts/persistence/columns.rb,
lib/activefacts/generate/rails/models.rb,
lib/activefacts/generate/transform/surrogate.rb
Class Method Summary collapse
Instance Method Summary collapse
-
#absorption_level ⇒ Object
How many of the initial references are involved in full absorption of an EntityType into this column’s table.
-
#absorption_references ⇒ Object
All references up to and including the first non-absorbing reference.
-
#comment ⇒ Object
The comment is the readings from the References expressed as a series of steps (not a full verbalisation).
-
#initialize(reference = nil) ⇒ Column
constructor
:nodoc:.
-
#is_auto_assigned ⇒ Object
This column is auto-assigned if it’s an auto-assigned value type and is not a foreign key.
- #is_auto_timestamp ⇒ Object
- #is_injected_surrogate ⇒ Object
-
#is_mandatory ⇒ Object
Is this column mandatory or nullable?.
-
#name(separator = "") ⇒ Object
A Column name is a sequence of names (derived from the to_roles of the References) appended by a separator string (pass nil to get the original array of names) The names to use is derived from the to_names of each Reference, modified by these rules: * A reference after the first one which is not a TypeInheritance but where the from object plays the sole role in the preferred identifier of the to entity is ignored, * A reference (after a name has been retained) which is a TypeInheritance retains the names of the subtype, * If the names retained so far end in XYZ and the to_names start with XYZ, remove the duplication * If we have retained the name of an entity, and this reference is the sole identifying role of an entity, and the identifying object has a name that is prefixed by the name of the object it identifies, remove the prefix and use just the suffix.
-
#prepend(reference) ⇒ Object
:nodoc:.
- #rails_name ⇒ Object
- #rails_type ⇒ Object
-
#references ⇒ Object
A Column is created from a path through an array of References to a ValueType.
-
#to_s ⇒ Object
:nodoc:.
-
#type ⇒ Object
What’s the underlying SQL data type of this column?.
Constructor Details
#initialize(reference = nil) ⇒ Column
:nodoc:
23 24 25 |
# File 'lib/activefacts/persistence/columns.rb', line 23 def initialize(reference = nil) #:nodoc: references << reference if reference end |
Class Method Details
.name(refs, separator = "") ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 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 |
# File 'lib/activefacts/persistence/columns.rb', line 69 def self.name(refs, separator = "") last_names = [] names = refs. inject([]) do |a, ref| # Skip any object after the first which is identified by this reference if ref != refs[0] and !ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) and ref.to and ref.to.is_a?(ActiveFacts::Metamodel::EntityType) and (role_ref = ref.to.preferred_identifier.role_sequence.all_role_ref.single) and role_ref.role == ref.from_role trace :columns, "Skipping #{ref}, identifies non-initial object" next a end names = ref.to_names(ref != refs.last) # When traversing type inheritances, keep the subtype name, not the supertype names as well: if a.size > 0 && ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) if ref.to != ref.fact_type.subtype # Did we already have the subtype? trace :columns, "Skipping supertype #{ref}" next a end trace :columns, "Eliding supertype in #{ref}" last_names.size.times { a.pop } # Remove the last names added elsif last_names.last && last_names.last == names[0][0...last_names.last.size] # When Xyz is followed by XyzID, truncate that to just ID trace :columns, "truncating repeated #{last_names.last} in #{names[0]}" names[0] = names[0][last_names.last.size..-1] names.shift if names[0] == '' elsif last_names.last == names[0] # Same, but where an underscore split up the words trace :columns, "truncating repeated name in #{names.inspect}" names.shift end # If the reference is to the single identifying role of the object_type making the reference, # strip the object_type name from the start of the reference role if a.size > 0 and (et = ref.from).is_a?(ActiveFacts::Metamodel::EntityType) and # This instead of the next 2 would apply to all identifying roles, but breaks some examples: # (role_ref = et.preferred_identifier.role_sequence.all_role_ref.detect{|rr| rr.role == ref.to_role}) and (role_ref = et.preferred_identifier.role_sequence.all_role_ref.single) and role_ref.role == ref.to_role and names[0][0...et.name.size].downcase == et.name.downcase trace :columns, "truncating transitive identifying role #{names.inspect}" names[0] = names[0][et.name.size..-1] names.shift if names[0] == "" end last_names = names a += names a end.elide_repeated_subsequences { |a, b| if a.is_a?(Array) a.map{|e| e.downcase} == b.map{|e| e.downcase} else a.downcase == b.downcase end } name_array = names.map{|n| n.sub(/^[a-z]/){|s| s.upcase}} separator ? name_array * separator : name_array end |
Instance Method Details
#absorption_level ⇒ Object
How many of the initial references are involved in full absorption of an EntityType into this column’s table
43 44 45 46 47 48 49 50 |
# File 'lib/activefacts/persistence/columns.rb', line 43 def absorption_level l = 0 @references.detect do |ref| l += 1 if ref.is_absorbing false end l end |
#absorption_references ⇒ Object
All references up to and including the first non-absorbing reference
33 34 35 36 37 38 39 40 |
# File 'lib/activefacts/persistence/columns.rb', line 33 def absorption_references @references.inject([]) do |array, ref| array << ref # puts "Column #{name} spans #{ref}, #{ref.is_absorbing ? "" : "not "} absorbing (#{ref.to.name} absorbs via #{ref.to.absorbed_via.inspect})" break array unless ref.is_absorbing array end end |
#comment ⇒ Object
The comment is the readings from the References expressed as a series of steps (not a full verbalisation)
178 179 180 181 182 |
# File 'lib/activefacts/persistence/columns.rb', line 178 def comment @references.map do |ref| ref.verbalised_path end.compact * " and " end |
#is_auto_assigned ⇒ Object
This column is auto-assigned if it’s an auto-assigned value type and is not a foreign key
145 146 147 148 149 150 151 |
# File 'lib/activefacts/persistence/columns.rb', line 145 def is_auto_assigned last_table_ref = references.reverse.detect{|r| r.from && r.from.is_table} (to = references[-1].to) && to.is_auto_assigned && references[0].from.identifier_columns.size == 1 && references[0].from == last_table_ref.from end |
#is_auto_timestamp ⇒ Object
234 235 236 237 238 239 240 241 |
# File 'lib/activefacts/generate/rails/models.rb', line 234 def case name('_') when /\A(created|updated)_(at|on)\Z/i true else false end end |
#is_injected_surrogate ⇒ Object
183 184 185 186 |
# File 'lib/activefacts/generate/transform/surrogate.rb', line 183 def is_injected_surrogate references.size == 1 and references[0].from_role == references[0].from.injected_surrogate_role end |
#is_mandatory ⇒ Object
Is this column mandatory or nullable?
138 139 140 141 142 |
# File 'lib/activefacts/persistence/columns.rb', line 138 def is_mandatory # Uncomment the following line for CWA unaries (not nullable, just T/F) # @references[-1].is_unary || !@references.detect{|ref| !ref.is_mandatory || ref.is_unary } end |
#name(separator = "") ⇒ Object
A Column name is a sequence of names (derived from the to_roles of the References) appended by a separator string (pass nil to get the original array of names) The names to use is derived from the to_names of each Reference, modified by these rules:
-
A reference after the first one which is not a TypeInheritance but where the from object plays the sole role in the preferred identifier of the to entity is ignored,
-
A reference (after a name has been retained) which is a TypeInheritance retains the names of the subtype,
-
If the names retained so far end in XYZ and the to_names start with XYZ, remove the duplication
-
If we have retained the name of an entity, and this reference is the sole identifying role of an entity, and the identifying object has a name that is prefixed by the name of the object it identifies, remove the prefix and use just the suffix.
65 66 67 |
# File 'lib/activefacts/persistence/columns.rb', line 65 def name(separator = "") self.class.name(@references, separator) end |
#prepend(reference) ⇒ Object
:nodoc:
52 53 54 55 |
# File 'lib/activefacts/persistence/columns.rb', line 52 def prepend reference #:nodoc: references.insert 0, reference self end |
#rails_name ⇒ Object
36 37 38 |
# File 'lib/activefacts/mapping/rails.rb', line 36 def rails_name Persistence::rails_singular_name(name('_')) end |
#rails_type ⇒ Object
40 41 42 43 44 45 46 47 48 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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/activefacts/mapping/rails.rb', line 40 def rails_type type_name, params, constraints = *type() rails_type = case type_name when /^Auto ?Counter$/i 'serial' # REVISIT: Need to detect surrogate ID fields and handle them correctly when /^[Ug]uid$/i 'uuid' when /^Unsigned ?Integer$/i, /^Integer$/i, /^Signed ?Integer$/i, /^Unsigned ?Small ?Integer$/i, /^Signed ?Small ?Integer$/i, /^Unsigned ?Tiny ?Integer$/i length = nil 'integer' when /^Decimal$/i 'decimal' when /^Float$/i, /^Double$/i, /^Real$/i 'float' when /^Fixed ?Length ?Text$/i, /^Char$/i 'string' when /^Variable ?Length ?Text$/i, /^String$/i 'string' when /^Large ?Length ?Text$/i, /^Text$/i 'text' when /^Date ?And ?Time$/i, /^Date ?Time$/i 'datetime' when /^Date$/i 'datetime' when /^Time$/i 'time' when /^Auto ?Time ?Stamp$/i 'timestamp' when /^Money$/i 'decimal' when /^Picture ?Raw ?Data$/i, /^Image$/i, /^Variable ?Length ?Raw ?Data$/i, /^Blob$/i 'binary' when /^BIT$/i, /^Boolean$/i 'boolean' else type_name # raise "ActiveRecord type unknown for standard type #{type}" end [rails_type, params[:length]] end |
#references ⇒ Object
A Column is created from a path through an array of References to a ValueType
28 29 30 |
# File 'lib/activefacts/persistence/columns.rb', line 28 def references @references ||= [] end |
#to_s ⇒ Object
:nodoc:
184 185 186 |
# File 'lib/activefacts/persistence/columns.rb', line 184 def to_s #:nodoc: "#{@references[0].from.name} column #{name('.')}" end |
#type ⇒ Object
What’s the underlying SQL data type of this column?
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/activefacts/persistence/columns.rb', line 154 def type params = {} constraints = [] return ["BIT", params, constraints] if references[-1].is_unary # It's a unary # Add a role value constraint # REVISIT: Can add join-role-value-constraints here, if we ever provide a way to define them if references[-1].to_role && references[-1].to_role.role_value_constraint constraints << references[-1].to_role.role_value_constraint end vt = references[-1].is_self_value ? references[-1].from : references[-1].to begin params[:length] ||= vt.length if vt.length.to_i != 0 params[:scale] ||= vt.scale if vt.scale.to_i != 0 constraints << vt.value_constraint if vt.value_constraint last_vt = vt vt = vt.supertype end while vt params[:underlying_type] = last_vt return [last_vt.name, params, constraints] end |