lib/activefacts/persistence/columns.rb in activefacts-1.0.2 vs lib/activefacts/persistence/columns.rb in activefacts-1.1.0
- old
+ new
@@ -76,32 +76,32 @@
!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
- debug :columns, "Skipping #{ref}, identifies non-initial object"
+ 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?
- debug :columns, "Skipping supertype #{ref}"
+ trace :columns, "Skipping supertype #{ref}"
next a
end
- debug :columns, "Eliding supertype in #{ref}"
+ 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
- debug :columns, "truncating repeated #{last_names.last} in #{names[0]}"
+ 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
- debug :columns, "truncating repeated name in #{names.inspect}"
+ 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
@@ -111,11 +111,11 @@
# (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
- debug :columns, "truncating transitive identifying role #{names.inspect}"
+ 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
@@ -175,14 +175,22 @@
end
# The comment is the readings from the References expressed as a series of steps (not a full verbalisation)
def comment
@references.map do |ref|
- (ref.is_mandatory ? "" : "maybe ") +
- (ref.fact_type && ref.fact_type.entity_type ? ref.fact_type.entity_type.name+" is where " : "") +
- ref.reading
- end * " and "
+ # REVISIT: Some contraction would be nice here
+ objectification = ref.fact_type && ref.fact_type.entity_type
+ involves = ''
+ if objectification && ref == @references.last
+ objectification = nil if ref.fact_type.all_role.size == 1 # Disregard the objectification of a trailing unary
+ involves = ref.to_role.link_fact_type.default_reading[ref.fact_type.entity_type.name.size..-1]
+ end
+ (objectification ? objectification.name + ' (in which ' : '') +
+ (ref.is_mandatory || ref.is_unary ? '' : 'maybe ') +
+ ref.reading +
+ (objectification ? ')'+involves : '')
+ end.compact * " and "
end
def to_s #:nodoc:
"#{@references[0].from.name} column #{name('.')}"
end
@@ -192,12 +200,38 @@
def columns(excluded_supertypes) #:nodoc:
kind = ""
cols =
if is_unary
kind = "unary "
- [Column.new()] +
- ((@to && @to.fact_type) ? @to.all_columns(excluded_supertypes) : [])
+ objectified_unary_columns =
+ ((@to && @to.fact_type) ? @to.all_columns(excluded_supertypes) : [])
+
+=begin
+ # This code omits the unary if it's objectified and that plays a mandatory role
+ first_mandatory_column = nil
+ if (@to && @to.fact_type)
+ trace :unary_col, "Deciding whether to skip unary column for #{inspect}" do
+ first_mandatory_column =
+ objectified_unary_columns.detect do |col| # Detect a mandatory column for the unary
+ trace :unary_col, "checking column #{col.name}" do
+ !col.references.detect do |ref|
+ trace :unary_col, "#{ref} is mandatory=#{ref.is_mandatory.inspect}"
+ !ref.is_mandatory
+ end
+ end
+ end
+ if is_from_objectified_fact && first_mandatory_column
+ trace :unary_col, "Skipping unary column for #{inspect} because #{first_mandatory_column.name} is mandatory"
+ end
+ end
+ end
+
+ (is_from_objectified_fact && first_mandatory_column ? [] : [Column.new()]) + # The unary itself, unless its objectified
+=end
+
+ [Column.new()] + # The unary itself
+ objectified_unary_columns
elsif is_self_value
kind = "self-role "
[Column.new()]
elsif is_simple_reference
@to.reference_columns(excluded_supertypes)
@@ -208,13 +242,13 @@
cols.each do |c|
c.prepend self
end
- debug :columns, "Columns from #{kind}#{self}" do
+ trace :columns, "Columns from #{kind}#{self}" do
cols.each {|c|
- debug :columns, "#{c}"
+ trace :columns, "#{c}"
}
end
end
end
end
@@ -237,11 +271,11 @@
# The ValueType class is defined in the metamodel; full documentation is not generated.
# This section shows the features relevant to relational Persistence.
class ValueType < DomainObjectType
# The identifier_columns for a ValueType can only ever be the self-value role that was injected
def identifier_columns
- debug :columns, "Identifier Columns for #{name}" do
+ trace :columns, "Identifier Columns for #{name}" do
raise "Illegal call to identifier_columns for absorbed ValueType #{name}" unless is_table
if isr = injected_surrogate_role
columns.select{|column| column.references[0].from_role == isr }
else
columns.select{|column| column.references[0] == self_value_reference}
@@ -250,11 +284,11 @@
end
# When creating a foreign key to this ValueType, what columns must we include?
# This must be a fresh copy, because the columns will have References prepended
def reference_columns(excluded_supertypes) #:nodoc:
- debug :columns, "Reference Columns for #{name}" do
+ trace :columns, "Reference Columns for #{name}" do
if is_table
if isr = injected_surrogate_role
ref_from = references_from.detect{|ref| ref.from_role == isr}
[ActiveFacts::Persistence::Column.new(ref_from)]
else
@@ -268,18 +302,18 @@
# When absorbing this ValueType, what columns must be absorbed?
# This must be a fresh copy, because the columns will have References prepended.
def all_columns(excluded_supertypes) #:nodoc:
columns = []
- debug :columns, "All Columns for #{name}" do
+ trace :columns, "All Columns for #{name}" do
if is_table
self_value_reference
else
columns << ActiveFacts::Persistence::Column.new
end
references_from.each do |ref|
- debug :columns, "Columns absorbed via #{ref}" do
+ trace :columns, "Columns absorbed via #{ref}" do
columns += ref.columns({})
end
end
end
columns
@@ -295,11 +329,11 @@
# The EntityType class is defined in the metamodel; full documentation is not generated.
# This section shows the features relevant to relational Persistence.
class EntityType < DomainObjectType
# The identifier_columns for an EntityType are the columns that result from the identifying roles
def identifier_columns
- debug :columns, "Identifier Columns for #{name}" do
+ trace :columns, "Identifier Columns for #{name}" do
if absorbed_via and
# If this is a subtype that has its own identification, use that.
(all_type_inheritance_as_subtype.size == 0 ||
all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
return absorbed_via.from.identifier_columns
@@ -314,20 +348,21 @@
end
# When creating a foreign key to this EntityType, what columns must we include (the identifier columns)?
# This must be a fresh copy, because the columns will have References prepended
def reference_columns(excluded_supertypes) #:nodoc:
- debug :columns, "Reference Columns for #{name}" do
+ trace :columns, "Reference Columns for #{name}" do
if absorbed_via and
# If this is not a subtype, or is a subtype that has its own identification, use the id.
(all_type_inheritance_as_subtype.size == 0 ||
all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
rc = absorbed_via.from.reference_columns(excluded_supertypes)
- # The absorbed_via reference gets skipped here, ans also in object_type.rb
- debug :columns, "Skipping #{absorbed_via}"
- #rc.each{|col| col.prepend(absorbed_via)}
+ # The absorbed_via reference gets skipped here, and also in object_type.rb
+ trace :columns, "Skipping #{absorbed_via}"
+ absorbed_mirror ||= absorbed_via.reversed
+ rc.each{|col| col.prepend(absorbed_mirror)}
return rc
end
# REVISIT: Should have built preferred_identifier_references
preferred_identifier.role_sequence.all_role_ref.map do |role_ref|
@@ -342,11 +377,11 @@
end
# When absorbing this EntityType, what columns must be absorbed?
# This must be a fresh copy, because the columns will have References prepended.
def all_columns(excluded_supertypes) #:nodoc:
- debug :columns, "All Columns for #{name}" do
+ trace :columns, "All Columns for #{name}" do
columns = []
sups = supertypes
pi_roles = preferred_identifier.role_sequence.all_role_ref.map{|rr| rr.role}
references_from.sort_by do |ref|
# Put supertypes first, in order, then PI roles, non-subtype references by name, then subtypes by name:
@@ -355,14 +390,14 @@
next [1, p] if p = pi_roles.index(ref.to_role)
next [2, ref.to_names]
end
[3, ref.to_names]
end.each do |ref|
- debug :columns, "Columns absorbed via #{ref}" do
+ trace :columns, "Columns absorbed via #{ref}" do
if (ref.role_type == :supertype)
if excluded_supertypes[ref.to]
- debug :columns, "Exclude #{ref.to.name}, we already inherited it"
+ trace :columns, "Exclude #{ref.to.name}, we already inherited it"
next
end
next if (ref.to.absorbed_via != ref)
excluded_supertypes[ref.to] = true
@@ -390,23 +425,23 @@
def populate_all_columns #:nodoc:
# REVISIT: Is now a good time to apply schema transforms or should this be more explicit?
finish_schema
- debug :columns, "Populating all columns" do
+ trace :columns, "Populating all columns" do
all_object_type.each do |object_type|
next if !object_type.is_table
- debug :columns, "Populating columns for table #{object_type.name}" do
+ trace :columns, "Populating columns for table #{object_type.name}" do
object_type.populate_columns
end
end
end
- debug :columns, "Finished columns" do
+ trace :columns, "Finished columns" do
all_object_type.each do |object_type|
next if !object_type.is_table
- debug :columns, "Finished columns for table #{object_type.name}" do
+ trace :columns, "Finished columns for table #{object_type.name}" do
object_type.columns.each do |column|
- debug :columns, "#{column}"
+ trace :columns, "#{column}"
end
end
end
end
end