activefacts 1.6.0 → 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +21 -0
- data/README.md +60 -0
- data/Rakefile +3 -80
- data/activefacts.gemspec +36 -0
- data/bin/afgen +4 -2
- data/bin/cql +5 -1
- data/lib/activefacts.rb +3 -12
- data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
- data/lib/activefacts/version.rb +2 -2
- metadata +48 -296
- data/History.txt +0 -4
- data/LICENSE +0 -19
- data/Manifest.txt +0 -165
- data/README.rdoc +0 -81
- data/css/offline.css +0 -3
- data/css/orm2.css +0 -124
- data/css/print.css +0 -8
- data/css/style-print.css +0 -357
- data/css/style.css +0 -387
- data/download.html +0 -110
- data/examples/CQL/Address.cql +0 -44
- data/examples/CQL/Blog.cql +0 -54
- data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
- data/examples/CQL/Death.cql +0 -17
- data/examples/CQL/Diplomacy.cql +0 -48
- data/examples/CQL/Genealogy.cql +0 -98
- data/examples/CQL/Insurance.cql +0 -320
- data/examples/CQL/Marriage.cql +0 -18
- data/examples/CQL/Metamodel.cql +0 -493
- data/examples/CQL/Monogamy.cql +0 -24
- data/examples/CQL/MultiInheritance.cql +0 -22
- data/examples/CQL/NonRoleId.cql +0 -14
- data/examples/CQL/OddIdentifier.cql +0 -18
- data/examples/CQL/OilSupply.cql +0 -53
- data/examples/CQL/OneToOnes.cql +0 -17
- data/examples/CQL/Orienteering.cql +0 -111
- data/examples/CQL/PersonPlaysGame.cql +0 -18
- data/examples/CQL/RedundantDependency.cql +0 -34
- data/examples/CQL/SchoolActivities.cql +0 -33
- data/examples/CQL/SeparateSubtype.cql +0 -30
- data/examples/CQL/ServiceDirector.cql +0 -276
- data/examples/CQL/SimplestUnary.cql +0 -12
- data/examples/CQL/Supervision.cql +0 -34
- data/examples/CQL/WaiterTips.cql +0 -33
- data/examples/CQL/Warehousing.cql +0 -101
- data/examples/CQL/WindowInRoomInBldg.cql +0 -28
- data/examples/CQL/unit.cql +0 -474
- data/examples/index.html +0 -420
- data/examples/intro.html +0 -327
- data/examples/local.css +0 -24
- data/index.html +0 -111
- data/lib/activefacts/cql.rb +0 -35
- data/lib/activefacts/cql/CQLParser.treetop +0 -158
- data/lib/activefacts/cql/Context.treetop +0 -48
- data/lib/activefacts/cql/Expressions.treetop +0 -67
- data/lib/activefacts/cql/FactTypes.treetop +0 -358
- data/lib/activefacts/cql/Language/English.treetop +0 -315
- data/lib/activefacts/cql/LexicalRules.treetop +0 -253
- data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
- data/lib/activefacts/cql/Rakefile +0 -14
- data/lib/activefacts/cql/Terms.treetop +0 -183
- data/lib/activefacts/cql/ValueTypes.treetop +0 -202
- data/lib/activefacts/cql/compiler.rb +0 -156
- data/lib/activefacts/cql/compiler/clause.rb +0 -1137
- data/lib/activefacts/cql/compiler/constraint.rb +0 -581
- data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
- data/lib/activefacts/cql/compiler/expression.rb +0 -443
- data/lib/activefacts/cql/compiler/fact.rb +0 -390
- data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
- data/lib/activefacts/cql/compiler/query.rb +0 -106
- data/lib/activefacts/cql/compiler/shared.rb +0 -161
- data/lib/activefacts/cql/compiler/value_type.rb +0 -174
- data/lib/activefacts/cql/nodes.rb +0 -49
- data/lib/activefacts/cql/parser.rb +0 -241
- data/lib/activefacts/dependency_analyser.rb +0 -182
- data/lib/activefacts/generate/absorption.rb +0 -70
- data/lib/activefacts/generate/composition.rb +0 -118
- data/lib/activefacts/generate/cql.rb +0 -714
- data/lib/activefacts/generate/dm.rb +0 -279
- data/lib/activefacts/generate/help.rb +0 -64
- data/lib/activefacts/generate/helpers/inject.rb +0 -16
- data/lib/activefacts/generate/helpers/oo.rb +0 -162
- data/lib/activefacts/generate/helpers/ordered.rb +0 -605
- data/lib/activefacts/generate/helpers/rails.rb +0 -57
- data/lib/activefacts/generate/html/glossary.rb +0 -461
- data/lib/activefacts/generate/json.rb +0 -337
- data/lib/activefacts/generate/null.rb +0 -32
- data/lib/activefacts/generate/rails/models.rb +0 -246
- data/lib/activefacts/generate/rails/schema.rb +0 -216
- data/lib/activefacts/generate/records.rb +0 -46
- data/lib/activefacts/generate/ruby.rb +0 -133
- data/lib/activefacts/generate/sql/mysql.rb +0 -280
- data/lib/activefacts/generate/sql/server.rb +0 -273
- data/lib/activefacts/generate/stats.rb +0 -69
- data/lib/activefacts/generate/text.rb +0 -27
- data/lib/activefacts/generate/topics.rb +0 -265
- data/lib/activefacts/generate/traits/datavault.rb +0 -241
- data/lib/activefacts/generate/traits/oo.rb +0 -73
- data/lib/activefacts/generate/traits/ordered.rb +0 -33
- data/lib/activefacts/generate/traits/ruby.rb +0 -210
- data/lib/activefacts/generate/transform/datavault.rb +0 -266
- data/lib/activefacts/generate/transform/surrogate.rb +0 -214
- data/lib/activefacts/generate/version.rb +0 -26
- data/lib/activefacts/input/cql.rb +0 -43
- data/lib/activefacts/input/orm.rb +0 -1636
- data/lib/activefacts/mapping/rails.rb +0 -132
- data/lib/activefacts/persistence.rb +0 -15
- data/lib/activefacts/persistence/columns.rb +0 -446
- data/lib/activefacts/persistence/foreignkey.rb +0 -187
- data/lib/activefacts/persistence/index.rb +0 -240
- data/lib/activefacts/persistence/object_type.rb +0 -198
- data/lib/activefacts/persistence/reference.rb +0 -434
- data/lib/activefacts/persistence/tables.rb +0 -380
- data/lib/activefacts/registry.rb +0 -11
- data/lib/activefacts/support.rb +0 -132
- data/lib/activefacts/vocabulary.rb +0 -9
- data/lib/activefacts/vocabulary/extensions.rb +0 -1348
- data/lib/activefacts/vocabulary/metamodel.rb +0 -570
- data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
- data/script/txt2html +0 -71
- data/spec/absorption_spec.rb +0 -95
- data/spec/cql/comparison_spec.rb +0 -89
- data/spec/cql/context_spec.rb +0 -94
- data/spec/cql/contractions_spec.rb +0 -224
- data/spec/cql/deontic_spec.rb +0 -88
- data/spec/cql/entity_type_spec.rb +0 -320
- data/spec/cql/expressions_spec.rb +0 -66
- data/spec/cql/fact_type_matching_spec.rb +0 -338
- data/spec/cql/french_spec.rb +0 -21
- data/spec/cql/parser/bad_literals_spec.rb +0 -86
- data/spec/cql/parser/constraints_spec.rb +0 -19
- data/spec/cql/parser/entity_types_spec.rb +0 -106
- data/spec/cql/parser/expressions_spec.rb +0 -199
- data/spec/cql/parser/fact_types_spec.rb +0 -44
- data/spec/cql/parser/literals_spec.rb +0 -312
- data/spec/cql/parser/pragmas_spec.rb +0 -89
- data/spec/cql/parser/value_types_spec.rb +0 -42
- data/spec/cql/role_matching_spec.rb +0 -148
- data/spec/cql/samples_spec.rb +0 -244
- data/spec/cql_cql_spec.rb +0 -73
- data/spec/cql_dm_spec.rb +0 -136
- data/spec/cql_mysql_spec.rb +0 -69
- data/spec/cql_parse_spec.rb +0 -34
- data/spec/cql_ruby_spec.rb +0 -73
- data/spec/cql_sql_spec.rb +0 -72
- data/spec/cql_symbol_tables_spec.rb +0 -261
- data/spec/cqldump_spec.rb +0 -170
- data/spec/helpers/array_matcher.rb +0 -23
- data/spec/helpers/ctrl_c_support.rb +0 -52
- data/spec/helpers/diff_matcher.rb +0 -39
- data/spec/helpers/file_matcher.rb +0 -34
- data/spec/helpers/parse_to_ast_matcher.rb +0 -80
- data/spec/helpers/string_matcher.rb +0 -30
- data/spec/helpers/test_parser.rb +0 -15
- data/spec/norma_cql_spec.rb +0 -66
- data/spec/norma_ruby_spec.rb +0 -62
- data/spec/norma_ruby_sql_spec.rb +0 -107
- data/spec/norma_sql_spec.rb +0 -57
- data/spec/norma_tables_spec.rb +0 -95
- data/spec/ruby_api_spec.rb +0 -23
- data/spec/spec_helper.rb +0 -35
- data/spec/transform_surrogate_spec.rb +0 -59
- data/status.html +0 -138
- data/why.html +0 -60
@@ -1,132 +0,0 @@
|
|
1
|
-
require 'activefacts/vocabulary'
|
2
|
-
require 'activefacts/persistence'
|
3
|
-
require 'active_support'
|
4
|
-
require 'digest/sha1'
|
5
|
-
|
6
|
-
module ActiveFacts
|
7
|
-
module Persistence
|
8
|
-
def self.rails_name_trunc name
|
9
|
-
if name.length > 63
|
10
|
-
hash = Digest::SHA1.hexdigest name
|
11
|
-
name = name[0, 53] + '__' + hash[0, 8]
|
12
|
-
end
|
13
|
-
name
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.rails_plural_name name
|
17
|
-
# Crunch spaces and pluralise the first part, all in snake_case
|
18
|
-
name.pop if name.is_a?(Array) and name.last == []
|
19
|
-
name = name[0]*'_' if name.is_a?(Array) and name.size == 1
|
20
|
-
if name.is_a?(Array)
|
21
|
-
name = ActiveSupport::Inflector.tableize((name[0]*'_').gsub(/\s+/, '_')) +
|
22
|
-
'_' +
|
23
|
-
ActiveSupport::Inflector.underscore((name[1..-1].flatten*'_').gsub(/\s+/, '_'))
|
24
|
-
else
|
25
|
-
ActiveSupport::Inflector.tableize(name.gsub(/\s+/, '_'))
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.rails_singular_name name
|
30
|
-
# Crunch spaces and convert to snake_case
|
31
|
-
name = name.flatten*'_' if name.is_a?(Array)
|
32
|
-
ActiveSupport::Inflector.underscore(name.gsub(/\s+/, '_'))
|
33
|
-
end
|
34
|
-
|
35
|
-
class Column
|
36
|
-
def rails_name
|
37
|
-
Persistence::rails_singular_name(name('_'))
|
38
|
-
end
|
39
|
-
|
40
|
-
def rails_type
|
41
|
-
type_name, params, constraints = *type()
|
42
|
-
rails_type = case type_name
|
43
|
-
when /^Auto ?Counter$/i
|
44
|
-
'serial' # REVISIT: Need to detect surrogate ID fields and handle them correctly
|
45
|
-
|
46
|
-
when /^[Ug]uid$/i
|
47
|
-
'uuid'
|
48
|
-
|
49
|
-
when /^Unsigned ?Integer$/i,
|
50
|
-
/^Integer$/i,
|
51
|
-
/^Signed ?Integer$/i,
|
52
|
-
/^Unsigned ?Small ?Integer$/i,
|
53
|
-
/^Signed ?Small ?Integer$/i,
|
54
|
-
/^Unsigned ?Tiny ?Integer$/i
|
55
|
-
length = nil
|
56
|
-
'integer'
|
57
|
-
|
58
|
-
when /^Decimal$/i
|
59
|
-
'decimal'
|
60
|
-
|
61
|
-
when /^Float$/i, /^Double$/i, /^Real$/i
|
62
|
-
'float'
|
63
|
-
|
64
|
-
when /^Fixed ?Length ?Text$/i, /^Char$/i
|
65
|
-
'string'
|
66
|
-
when /^Variable ?Length ?Text$/i, /^String$/i
|
67
|
-
'string'
|
68
|
-
when /^Large ?Length ?Text$/i, /^Text$/i
|
69
|
-
'text'
|
70
|
-
|
71
|
-
when /^Date ?And ?Time$/i, /^Date ?Time$/i
|
72
|
-
'datetime'
|
73
|
-
when /^Date$/i
|
74
|
-
'datetime'
|
75
|
-
when /^Time$/i
|
76
|
-
'time'
|
77
|
-
when /^Auto ?Time ?Stamp$/i
|
78
|
-
'timestamp'
|
79
|
-
|
80
|
-
when /^Money$/i
|
81
|
-
'decimal'
|
82
|
-
when /^Picture ?Raw ?Data$/i, /^Image$/i, /^Variable ?Length ?Raw ?Data$/i, /^Blob$/i
|
83
|
-
'binary'
|
84
|
-
when /^BIT$/i, /^Boolean$/i
|
85
|
-
'boolean'
|
86
|
-
else
|
87
|
-
type_name # raise "ActiveRecord type unknown for standard type #{type}"
|
88
|
-
end
|
89
|
-
[rails_type, params[:length]]
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
class Index
|
94
|
-
def rails_name
|
95
|
-
column_names = columns.map{|c| c.rails_name }
|
96
|
-
index_name = "index_#{on.rails_name+'_on_'+column_names*'_'}"
|
97
|
-
Persistence.rails_name_trunc index_name
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
class ForeignKey
|
102
|
-
def rails_from_association_name
|
103
|
-
Persistence::rails_singular_name(to_name.join('_'))
|
104
|
-
end
|
105
|
-
|
106
|
-
def rails_to_association
|
107
|
-
jump = jump_reference
|
108
|
-
if jump.is_one_to_one
|
109
|
-
[ "has_one", Persistence::rails_singular_name(from_name)]
|
110
|
-
else
|
111
|
-
[ "has_many", Persistence::rails_plural_name(from_name)]
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
module Metamodel
|
118
|
-
class ObjectType
|
119
|
-
def rails_name
|
120
|
-
Persistence::rails_plural_name(name)
|
121
|
-
end
|
122
|
-
|
123
|
-
def rails_singular_name
|
124
|
-
Persistence::rails_singular_name(name)
|
125
|
-
end
|
126
|
-
|
127
|
-
def rails_class_name
|
128
|
-
ActiveSupport::Inflector.camelize(name.gsub(/\s+/, '_'))
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# ActiveFacts Relational mapping and persistence.
|
3
|
-
#
|
4
|
-
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
5
|
-
#
|
6
|
-
|
7
|
-
# These files are concerned with calculating a relational schema for a vocabulary:
|
8
|
-
require 'activefacts/persistence/reference'
|
9
|
-
require 'activefacts/persistence/tables'
|
10
|
-
require 'activefacts/persistence/columns'
|
11
|
-
require 'activefacts/persistence/foreignkey'
|
12
|
-
require 'activefacts/persistence/index'
|
13
|
-
|
14
|
-
# These extend the API classes with relational awareness:
|
15
|
-
require 'activefacts/persistence/object_type'
|
@@ -1,446 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# ActiveFacts Relational mapping and persistence.
|
3
|
-
# Columns in a relational table; each is derived from a sequence of References.
|
4
|
-
#
|
5
|
-
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
6
|
-
#
|
7
|
-
# Each Reference from a ObjectType creates one or more Columns.
|
8
|
-
# A reference to a simple valuetype creates a single column, as
|
9
|
-
# does a reference to a table entity identified by a single value.
|
10
|
-
#
|
11
|
-
# When referring to a object_type that doesn't have its own table,
|
12
|
-
# all references from that object_type are absorbed into this one.
|
13
|
-
#
|
14
|
-
# When multiple values identify an entity that does have its own
|
15
|
-
# table, a reference to that entity creates multiple columns,
|
16
|
-
# a multi-part foreign key.
|
17
|
-
#
|
18
|
-
|
19
|
-
module ActiveFacts
|
20
|
-
module Persistence #:nodoc:
|
21
|
-
|
22
|
-
class Column
|
23
|
-
def initialize(reference = nil) #:nodoc:
|
24
|
-
references << reference if reference
|
25
|
-
end
|
26
|
-
|
27
|
-
# A Column is created from a path through an array of References to a ValueType
|
28
|
-
def references
|
29
|
-
@references ||= []
|
30
|
-
end
|
31
|
-
|
32
|
-
# All references up to and including the first non-absorbing reference
|
33
|
-
def absorption_references
|
34
|
-
@references.inject([]) do |array, ref|
|
35
|
-
array << ref
|
36
|
-
# puts "Column #{name} spans #{ref}, #{ref.is_absorbing ? "" : "not "} absorbing (#{ref.to.name} absorbs via #{ref.to.absorbed_via.inspect})"
|
37
|
-
break array unless ref.is_absorbing
|
38
|
-
array
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# How many of the initial references are involved in full absorption of an EntityType into this column's table
|
43
|
-
def absorption_level
|
44
|
-
l = 0
|
45
|
-
@references.detect do |ref|
|
46
|
-
l += 1 if ref.is_absorbing
|
47
|
-
false
|
48
|
-
end
|
49
|
-
l
|
50
|
-
end
|
51
|
-
|
52
|
-
def prepend reference #:nodoc:
|
53
|
-
references.insert 0, reference
|
54
|
-
self
|
55
|
-
end
|
56
|
-
|
57
|
-
# A Column name is a sequence of names (derived from the to_roles of the References)
|
58
|
-
# appended by a separator string (pass nil to get the original array of names)
|
59
|
-
# The names to use is derived from the to_names of each Reference,
|
60
|
-
# modified by these rules:
|
61
|
-
# * 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,
|
62
|
-
# * A reference (after a name has been retained) which is a TypeInheritance retains the names of the subtype,
|
63
|
-
# * If the names retained so far end in XYZ and the to_names start with XYZ, remove the duplication
|
64
|
-
# * 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
|
-
def name(separator = "")
|
66
|
-
self.class.name(@references, separator)
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.name(refs, separator = "")
|
70
|
-
last_names = []
|
71
|
-
names = refs.
|
72
|
-
inject([]) do |a, ref|
|
73
|
-
|
74
|
-
# Skip any object after the first which is identified by this reference
|
75
|
-
if ref != refs[0] and
|
76
|
-
!ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) and
|
77
|
-
ref.to and
|
78
|
-
ref.to.is_a?(ActiveFacts::Metamodel::EntityType) and
|
79
|
-
(role_ref = ref.to.preferred_identifier.role_sequence.all_role_ref.single) and
|
80
|
-
role_ref.role == ref.from_role
|
81
|
-
trace :columns, "Skipping #{ref}, identifies non-initial object"
|
82
|
-
next a
|
83
|
-
end
|
84
|
-
|
85
|
-
names = ref.to_names(ref != refs.last)
|
86
|
-
|
87
|
-
# When traversing type inheritances, keep the subtype name, not the supertype names as well:
|
88
|
-
if a.size > 0 && ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
89
|
-
if ref.to != ref.fact_type.subtype # Did we already have the subtype?
|
90
|
-
trace :columns, "Skipping supertype #{ref}"
|
91
|
-
next a
|
92
|
-
end
|
93
|
-
trace :columns, "Eliding supertype in #{ref}"
|
94
|
-
last_names.size.times { a.pop } # Remove the last names added
|
95
|
-
elsif last_names.last && last_names.last == names[0][0...last_names.last.size]
|
96
|
-
# When Xyz is followed by XyzID, truncate that to just ID
|
97
|
-
trace :columns, "truncating repeated #{last_names.last} in #{names[0]}"
|
98
|
-
names[0] = names[0][last_names.last.size..-1]
|
99
|
-
names.shift if names[0] == ''
|
100
|
-
elsif last_names.last == names[0]
|
101
|
-
# Same, but where an underscore split up the words
|
102
|
-
trace :columns, "truncating repeated name in #{names.inspect}"
|
103
|
-
names.shift
|
104
|
-
end
|
105
|
-
|
106
|
-
# If the reference is to the single identifying role of the object_type making the reference,
|
107
|
-
# strip the object_type name from the start of the reference role
|
108
|
-
if a.size > 0 and
|
109
|
-
(et = ref.from).is_a?(ActiveFacts::Metamodel::EntityType) and
|
110
|
-
# This instead of the next 2 would apply to all identifying roles, but breaks some examples:
|
111
|
-
# (role_ref = et.preferred_identifier.role_sequence.all_role_ref.detect{|rr| rr.role == ref.to_role}) and
|
112
|
-
(role_ref = et.preferred_identifier.role_sequence.all_role_ref.single) and
|
113
|
-
role_ref.role == ref.to_role and
|
114
|
-
names[0][0...et.name.size].downcase == et.name.downcase
|
115
|
-
|
116
|
-
trace :columns, "truncating transitive identifying role #{names.inspect}"
|
117
|
-
names[0] = names[0][et.name.size..-1]
|
118
|
-
names.shift if names[0] == ""
|
119
|
-
end
|
120
|
-
|
121
|
-
last_names = names
|
122
|
-
|
123
|
-
a += names
|
124
|
-
a
|
125
|
-
end.elide_repeated_subsequences { |a, b|
|
126
|
-
if a.is_a?(Array)
|
127
|
-
a.map{|e| e.downcase} == b.map{|e| e.downcase}
|
128
|
-
else
|
129
|
-
a.downcase == b.downcase
|
130
|
-
end
|
131
|
-
}
|
132
|
-
|
133
|
-
name_array = names.map{|n| n.sub(/^[a-z]/){|s| s.upcase}}
|
134
|
-
separator ? name_array * separator : name_array
|
135
|
-
end
|
136
|
-
|
137
|
-
# Is this column mandatory or nullable?
|
138
|
-
def is_mandatory
|
139
|
-
# Uncomment the following line for CWA unaries (not nullable, just T/F)
|
140
|
-
# @references[-1].is_unary ||
|
141
|
-
!@references.detect{|ref| !ref.is_mandatory || ref.is_unary }
|
142
|
-
end
|
143
|
-
|
144
|
-
# This column is auto-assigned if it's an auto-assigned value type and is not a foreign key
|
145
|
-
def is_auto_assigned
|
146
|
-
last_table_ref = references.reverse.detect{|r| r.from && r.from.is_table}
|
147
|
-
(to = references[-1].to) &&
|
148
|
-
to.is_auto_assigned &&
|
149
|
-
references[0].from.identifier_columns.size == 1 &&
|
150
|
-
references[0].from == last_table_ref.from
|
151
|
-
end
|
152
|
-
|
153
|
-
# What's the underlying SQL data type of this column?
|
154
|
-
def type
|
155
|
-
params = {}
|
156
|
-
constraints = []
|
157
|
-
return ["BIT", params, constraints] if references[-1].is_unary # It's a unary
|
158
|
-
|
159
|
-
# Add a role value constraint
|
160
|
-
# REVISIT: Can add join-role-value-constraints here, if we ever provide a way to define them
|
161
|
-
if references[-1].to_role && references[-1].to_role.role_value_constraint
|
162
|
-
constraints << references[-1].to_role.role_value_constraint
|
163
|
-
end
|
164
|
-
|
165
|
-
vt = references[-1].is_self_value ? references[-1].from : references[-1].to
|
166
|
-
begin
|
167
|
-
params[:length] ||= vt.length if vt.length.to_i != 0
|
168
|
-
params[:scale] ||= vt.scale if vt.scale.to_i != 0
|
169
|
-
constraints << vt.value_constraint if vt.value_constraint
|
170
|
-
last_vt = vt
|
171
|
-
vt = vt.supertype
|
172
|
-
end while vt
|
173
|
-
params[:underlying_type] = last_vt
|
174
|
-
return [last_vt.name, params, constraints]
|
175
|
-
end
|
176
|
-
|
177
|
-
# The comment is the readings from the References expressed as a series of steps (not a full verbalisation)
|
178
|
-
def comment
|
179
|
-
@references.map do |ref|
|
180
|
-
ref.verbalised_path
|
181
|
-
end.compact * " and "
|
182
|
-
end
|
183
|
-
|
184
|
-
def to_s #:nodoc:
|
185
|
-
"#{@references[0].from.name} column #{name('.')}"
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
class Reference
|
190
|
-
def columns(excluded_supertypes) #:nodoc:
|
191
|
-
kind = ""
|
192
|
-
cols =
|
193
|
-
if is_unary
|
194
|
-
kind = "unary "
|
195
|
-
objectified_unary_columns =
|
196
|
-
((@to && @to.fact_type) ? @to.all_columns(excluded_supertypes) : [])
|
197
|
-
|
198
|
-
=begin
|
199
|
-
# This code omits the unary if it's objectified and that plays a mandatory role
|
200
|
-
first_mandatory_column = nil
|
201
|
-
if (@to && @to.fact_type)
|
202
|
-
trace :unary_col, "Deciding whether to skip unary column for #{inspect}" do
|
203
|
-
first_mandatory_column =
|
204
|
-
objectified_unary_columns.detect do |col| # Detect a mandatory column for the unary
|
205
|
-
trace :unary_col, "checking column #{col.name}" do
|
206
|
-
!col.references.detect do |ref|
|
207
|
-
trace :unary_col, "#{ref} is mandatory=#{ref.is_mandatory.inspect}"
|
208
|
-
!ref.is_mandatory
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
if is_from_objectified_fact && first_mandatory_column
|
213
|
-
trace :unary_col, "Skipping unary column for #{inspect} because #{first_mandatory_column.name} is mandatory"
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
(is_from_objectified_fact && first_mandatory_column ? [] : [Column.new()]) + # The unary itself, unless its objectified
|
219
|
-
=end
|
220
|
-
|
221
|
-
[Column.new()] + # The unary itself
|
222
|
-
objectified_unary_columns
|
223
|
-
elsif is_self_value
|
224
|
-
kind = "self-role "
|
225
|
-
[Column.new()]
|
226
|
-
elsif is_simple_reference
|
227
|
-
@to.reference_columns(excluded_supertypes)
|
228
|
-
else
|
229
|
-
kind = "absorbing "
|
230
|
-
@to.all_columns(excluded_supertypes)
|
231
|
-
end
|
232
|
-
|
233
|
-
cols.each do |c|
|
234
|
-
c.prepend self
|
235
|
-
end
|
236
|
-
|
237
|
-
trace :columns, "Columns from #{kind}#{self}" do
|
238
|
-
cols.each {|c|
|
239
|
-
trace :columns, "#{c}"
|
240
|
-
}
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
module Metamodel #:nodoc:
|
247
|
-
# The ObjectType class is defined in the metamodel; full documentation is not generated.
|
248
|
-
# This section shows the features relevant to relational Persistence.
|
249
|
-
class ObjectType
|
250
|
-
# The array of columns for this ObjectType's table
|
251
|
-
def columns
|
252
|
-
@columns || populate_columns
|
253
|
-
end
|
254
|
-
|
255
|
-
def populate_columns #:nodoc:
|
256
|
-
@columns =
|
257
|
-
all_columns({})
|
258
|
-
end
|
259
|
-
|
260
|
-
def wipe_columns
|
261
|
-
@columns = nil
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
# The ValueType class is defined in the metamodel; full documentation is not generated.
|
266
|
-
# This section shows the features relevant to relational Persistence.
|
267
|
-
class ValueType < DomainObjectType
|
268
|
-
# The identifier_columns for a ValueType can only ever be the self-value role that was injected
|
269
|
-
def identifier_columns
|
270
|
-
trace :columns, "Identifier Columns for #{name}" do
|
271
|
-
raise "Illegal call to identifier_columns for absorbed ValueType #{name}" unless is_table
|
272
|
-
if isr = injected_surrogate_role
|
273
|
-
columns.select{|column| column.references[0].from_role == isr }
|
274
|
-
else
|
275
|
-
columns.select{|column| column.references[0] == self_value_reference}
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
# When creating a foreign key to this ValueType, what columns must we include?
|
281
|
-
# This must be a fresh copy, because the columns will have References prepended
|
282
|
-
def reference_columns(excluded_supertypes) #:nodoc:
|
283
|
-
trace :columns, "Reference Columns for #{name}" do
|
284
|
-
if is_table
|
285
|
-
if isr = injected_surrogate_role
|
286
|
-
ref_from = references_from.detect{|ref| ref.from_role == isr}
|
287
|
-
[ActiveFacts::Persistence::Column.new(ref_from)]
|
288
|
-
else
|
289
|
-
[ActiveFacts::Persistence::Column.new(self_value_reference)]
|
290
|
-
end
|
291
|
-
else
|
292
|
-
[ActiveFacts::Persistence::Column.new]
|
293
|
-
end
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
# When absorbing this ValueType, what columns must be absorbed?
|
298
|
-
# This must be a fresh copy, because the columns will have References prepended.
|
299
|
-
def all_columns(excluded_supertypes) #:nodoc:
|
300
|
-
columns = []
|
301
|
-
trace :columns, "All Columns for #{name}" do
|
302
|
-
if is_table
|
303
|
-
self_value_reference
|
304
|
-
else
|
305
|
-
columns << ActiveFacts::Persistence::Column.new
|
306
|
-
end
|
307
|
-
references_from.each do |ref|
|
308
|
-
trace :columns, "Columns absorbed via #{ref}" do
|
309
|
-
columns += ref.columns({})
|
310
|
-
end
|
311
|
-
end
|
312
|
-
end
|
313
|
-
columns
|
314
|
-
end
|
315
|
-
|
316
|
-
# If someone asks for this, it's because it's needed, so create it.
|
317
|
-
def self_value_reference #:nodoc:
|
318
|
-
# Make a reference for the self-value column
|
319
|
-
@self_value_reference ||= ActiveFacts::Persistence::Reference.new(self, nil).tabulate
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
# The EntityType class is defined in the metamodel; full documentation is not generated.
|
324
|
-
# This section shows the features relevant to relational Persistence.
|
325
|
-
class EntityType < DomainObjectType
|
326
|
-
# The identifier_columns for an EntityType are the columns that result from the identifying roles
|
327
|
-
def identifier_columns
|
328
|
-
trace :columns, "Identifier Columns for #{name}" do
|
329
|
-
if absorbed_via and
|
330
|
-
# If this is a subtype that has its own identification, use that.
|
331
|
-
(all_type_inheritance_as_subtype.size == 0 ||
|
332
|
-
all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
|
333
|
-
return absorbed_via.from.identifier_columns
|
334
|
-
end
|
335
|
-
|
336
|
-
preferred_identifier.role_sequence.all_role_ref.map do |role_ref|
|
337
|
-
ref = references_from.detect {|ref| ref.to_role == role_ref.role}
|
338
|
-
|
339
|
-
columns.select{|column| column.references[0] == ref}
|
340
|
-
end.flatten
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
# When creating a foreign key to this EntityType, what columns must we include (the identifier columns)?
|
345
|
-
# This must be a fresh copy, because the columns will have References prepended
|
346
|
-
def reference_columns(excluded_supertypes) #:nodoc:
|
347
|
-
trace :columns, "Reference Columns for #{name}" do
|
348
|
-
|
349
|
-
if absorbed_via and
|
350
|
-
# If this is not a subtype, or is a subtype that has its own identification, use the id.
|
351
|
-
(all_type_inheritance_as_subtype.size == 0 ||
|
352
|
-
all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
|
353
|
-
rc = absorbed_via.from.reference_columns(excluded_supertypes)
|
354
|
-
# The absorbed_via reference gets skipped here, and also in object_type.rb
|
355
|
-
trace :columns, "Skipping #{absorbed_via}"
|
356
|
-
absorbed_mirror ||= absorbed_via.reversed
|
357
|
-
rc.each{|col| col.prepend(absorbed_mirror)}
|
358
|
-
return rc
|
359
|
-
end
|
360
|
-
|
361
|
-
# REVISIT: Should have built preferred_identifier_references
|
362
|
-
preferred_identifier.role_sequence.all_role_ref.map do |role_ref|
|
363
|
-
# REVISIT: Should index references by to_role:
|
364
|
-
ref = references_from.detect {|ref| ref.to_role == role_ref.role}
|
365
|
-
|
366
|
-
raise "reference for role #{role_ref.describe} not found on #{name} in #{references_from.size} references:\n\t#{references_from.map(&:to_s)*"\n\t"}" unless ref
|
367
|
-
|
368
|
-
ref.columns({})
|
369
|
-
end.flatten
|
370
|
-
end
|
371
|
-
end
|
372
|
-
|
373
|
-
# When absorbing this EntityType, what columns must be absorbed?
|
374
|
-
# This must be a fresh copy, because the columns will have References prepended.
|
375
|
-
def all_columns(excluded_supertypes) #:nodoc:
|
376
|
-
trace :columns, "All Columns for #{name}" do
|
377
|
-
columns = []
|
378
|
-
sups = supertypes
|
379
|
-
pi_roles = preferred_identifier.role_sequence.all_role_ref.map{|rr| rr.role}
|
380
|
-
references_from.sort_by do |ref|
|
381
|
-
# Put supertypes first, in order, then PI roles, non-subtype references by name, then subtypes by name:
|
382
|
-
next [0, p] if p = sups.index(ref.to)
|
383
|
-
if !ref.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
384
|
-
next [1, p] if p = pi_roles.index(ref.to_role)
|
385
|
-
next [2, ref.to_names]
|
386
|
-
end
|
387
|
-
[3, ref.to_names]
|
388
|
-
end.each do |ref|
|
389
|
-
trace :columns, "Columns absorbed via #{ref}" do
|
390
|
-
if (ref.role_type == :supertype)
|
391
|
-
if excluded_supertypes[ref.to]
|
392
|
-
trace :columns, "Exclude #{ref.to.name}, we already inherited it"
|
393
|
-
next
|
394
|
-
end
|
395
|
-
|
396
|
-
next if (ref.to.absorbed_via != ref)
|
397
|
-
excluded_supertypes[ref.to] = true
|
398
|
-
columns += ref.columns(excluded_supertypes)
|
399
|
-
else
|
400
|
-
columns += ref.columns({})
|
401
|
-
end
|
402
|
-
end
|
403
|
-
end
|
404
|
-
columns
|
405
|
-
end
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
# The Vocabulary class is defined in the metamodel; full documentation is not generated.
|
410
|
-
# This section shows the features relevant to relational Persistence.
|
411
|
-
class Vocabulary
|
412
|
-
# Make schema transformations like adding ValueType self-value columns (and later, Rails-friendly ID fields).
|
413
|
-
# Override this method to change the transformations
|
414
|
-
def finish_schema
|
415
|
-
all_object_type.each do |object_type|
|
416
|
-
object_type.self_value_reference if object_type.is_a?(ActiveFacts::Metamodel::ValueType) && object_type.is_table
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
def populate_all_columns #:nodoc:
|
421
|
-
# REVISIT: Is now a good time to apply schema transforms or should this be more explicit?
|
422
|
-
finish_schema
|
423
|
-
|
424
|
-
trace :columns, "Populating all columns" do
|
425
|
-
all_object_type.each do |object_type|
|
426
|
-
next if !object_type.is_table
|
427
|
-
trace :columns, "Populating columns for table #{object_type.name}" do
|
428
|
-
object_type.populate_columns
|
429
|
-
end
|
430
|
-
end
|
431
|
-
end
|
432
|
-
trace :columns, "Finished columns" do
|
433
|
-
all_object_type.each do |object_type|
|
434
|
-
next if !object_type.is_table
|
435
|
-
trace :columns, "Finished columns for table #{object_type.name}" do
|
436
|
-
object_type.columns.each do |column|
|
437
|
-
trace :columns, "#{column}"
|
438
|
-
end
|
439
|
-
end
|
440
|
-
end
|
441
|
-
end
|
442
|
-
end
|
443
|
-
end
|
444
|
-
|
445
|
-
end
|
446
|
-
end
|