activefacts 1.6.0 → 1.7.1

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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +60 -0
  8. data/Rakefile +3 -80
  9. data/activefacts.gemspec +36 -0
  10. data/bin/afgen +4 -2
  11. data/bin/cql +5 -1
  12. data/lib/activefacts.rb +3 -12
  13. data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
  14. data/lib/activefacts/version.rb +2 -2
  15. metadata +48 -296
  16. data/History.txt +0 -4
  17. data/LICENSE +0 -19
  18. data/Manifest.txt +0 -165
  19. data/README.rdoc +0 -81
  20. data/css/offline.css +0 -3
  21. data/css/orm2.css +0 -124
  22. data/css/print.css +0 -8
  23. data/css/style-print.css +0 -357
  24. data/css/style.css +0 -387
  25. data/download.html +0 -110
  26. data/examples/CQL/Address.cql +0 -44
  27. data/examples/CQL/Blog.cql +0 -54
  28. data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
  29. data/examples/CQL/Death.cql +0 -17
  30. data/examples/CQL/Diplomacy.cql +0 -48
  31. data/examples/CQL/Genealogy.cql +0 -98
  32. data/examples/CQL/Insurance.cql +0 -320
  33. data/examples/CQL/Marriage.cql +0 -18
  34. data/examples/CQL/Metamodel.cql +0 -493
  35. data/examples/CQL/Monogamy.cql +0 -24
  36. data/examples/CQL/MultiInheritance.cql +0 -22
  37. data/examples/CQL/NonRoleId.cql +0 -14
  38. data/examples/CQL/OddIdentifier.cql +0 -18
  39. data/examples/CQL/OilSupply.cql +0 -53
  40. data/examples/CQL/OneToOnes.cql +0 -17
  41. data/examples/CQL/Orienteering.cql +0 -111
  42. data/examples/CQL/PersonPlaysGame.cql +0 -18
  43. data/examples/CQL/RedundantDependency.cql +0 -34
  44. data/examples/CQL/SchoolActivities.cql +0 -33
  45. data/examples/CQL/SeparateSubtype.cql +0 -30
  46. data/examples/CQL/ServiceDirector.cql +0 -276
  47. data/examples/CQL/SimplestUnary.cql +0 -12
  48. data/examples/CQL/Supervision.cql +0 -34
  49. data/examples/CQL/WaiterTips.cql +0 -33
  50. data/examples/CQL/Warehousing.cql +0 -101
  51. data/examples/CQL/WindowInRoomInBldg.cql +0 -28
  52. data/examples/CQL/unit.cql +0 -474
  53. data/examples/index.html +0 -420
  54. data/examples/intro.html +0 -327
  55. data/examples/local.css +0 -24
  56. data/index.html +0 -111
  57. data/lib/activefacts/cql.rb +0 -35
  58. data/lib/activefacts/cql/CQLParser.treetop +0 -158
  59. data/lib/activefacts/cql/Context.treetop +0 -48
  60. data/lib/activefacts/cql/Expressions.treetop +0 -67
  61. data/lib/activefacts/cql/FactTypes.treetop +0 -358
  62. data/lib/activefacts/cql/Language/English.treetop +0 -315
  63. data/lib/activefacts/cql/LexicalRules.treetop +0 -253
  64. data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
  65. data/lib/activefacts/cql/Rakefile +0 -14
  66. data/lib/activefacts/cql/Terms.treetop +0 -183
  67. data/lib/activefacts/cql/ValueTypes.treetop +0 -202
  68. data/lib/activefacts/cql/compiler.rb +0 -156
  69. data/lib/activefacts/cql/compiler/clause.rb +0 -1137
  70. data/lib/activefacts/cql/compiler/constraint.rb +0 -581
  71. data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
  72. data/lib/activefacts/cql/compiler/expression.rb +0 -443
  73. data/lib/activefacts/cql/compiler/fact.rb +0 -390
  74. data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
  75. data/lib/activefacts/cql/compiler/query.rb +0 -106
  76. data/lib/activefacts/cql/compiler/shared.rb +0 -161
  77. data/lib/activefacts/cql/compiler/value_type.rb +0 -174
  78. data/lib/activefacts/cql/nodes.rb +0 -49
  79. data/lib/activefacts/cql/parser.rb +0 -241
  80. data/lib/activefacts/dependency_analyser.rb +0 -182
  81. data/lib/activefacts/generate/absorption.rb +0 -70
  82. data/lib/activefacts/generate/composition.rb +0 -118
  83. data/lib/activefacts/generate/cql.rb +0 -714
  84. data/lib/activefacts/generate/dm.rb +0 -279
  85. data/lib/activefacts/generate/help.rb +0 -64
  86. data/lib/activefacts/generate/helpers/inject.rb +0 -16
  87. data/lib/activefacts/generate/helpers/oo.rb +0 -162
  88. data/lib/activefacts/generate/helpers/ordered.rb +0 -605
  89. data/lib/activefacts/generate/helpers/rails.rb +0 -57
  90. data/lib/activefacts/generate/html/glossary.rb +0 -461
  91. data/lib/activefacts/generate/json.rb +0 -337
  92. data/lib/activefacts/generate/null.rb +0 -32
  93. data/lib/activefacts/generate/rails/models.rb +0 -246
  94. data/lib/activefacts/generate/rails/schema.rb +0 -216
  95. data/lib/activefacts/generate/records.rb +0 -46
  96. data/lib/activefacts/generate/ruby.rb +0 -133
  97. data/lib/activefacts/generate/sql/mysql.rb +0 -280
  98. data/lib/activefacts/generate/sql/server.rb +0 -273
  99. data/lib/activefacts/generate/stats.rb +0 -69
  100. data/lib/activefacts/generate/text.rb +0 -27
  101. data/lib/activefacts/generate/topics.rb +0 -265
  102. data/lib/activefacts/generate/traits/datavault.rb +0 -241
  103. data/lib/activefacts/generate/traits/oo.rb +0 -73
  104. data/lib/activefacts/generate/traits/ordered.rb +0 -33
  105. data/lib/activefacts/generate/traits/ruby.rb +0 -210
  106. data/lib/activefacts/generate/transform/datavault.rb +0 -266
  107. data/lib/activefacts/generate/transform/surrogate.rb +0 -214
  108. data/lib/activefacts/generate/version.rb +0 -26
  109. data/lib/activefacts/input/cql.rb +0 -43
  110. data/lib/activefacts/input/orm.rb +0 -1636
  111. data/lib/activefacts/mapping/rails.rb +0 -132
  112. data/lib/activefacts/persistence.rb +0 -15
  113. data/lib/activefacts/persistence/columns.rb +0 -446
  114. data/lib/activefacts/persistence/foreignkey.rb +0 -187
  115. data/lib/activefacts/persistence/index.rb +0 -240
  116. data/lib/activefacts/persistence/object_type.rb +0 -198
  117. data/lib/activefacts/persistence/reference.rb +0 -434
  118. data/lib/activefacts/persistence/tables.rb +0 -380
  119. data/lib/activefacts/registry.rb +0 -11
  120. data/lib/activefacts/support.rb +0 -132
  121. data/lib/activefacts/vocabulary.rb +0 -9
  122. data/lib/activefacts/vocabulary/extensions.rb +0 -1348
  123. data/lib/activefacts/vocabulary/metamodel.rb +0 -570
  124. data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
  125. data/script/txt2html +0 -71
  126. data/spec/absorption_spec.rb +0 -95
  127. data/spec/cql/comparison_spec.rb +0 -89
  128. data/spec/cql/context_spec.rb +0 -94
  129. data/spec/cql/contractions_spec.rb +0 -224
  130. data/spec/cql/deontic_spec.rb +0 -88
  131. data/spec/cql/entity_type_spec.rb +0 -320
  132. data/spec/cql/expressions_spec.rb +0 -66
  133. data/spec/cql/fact_type_matching_spec.rb +0 -338
  134. data/spec/cql/french_spec.rb +0 -21
  135. data/spec/cql/parser/bad_literals_spec.rb +0 -86
  136. data/spec/cql/parser/constraints_spec.rb +0 -19
  137. data/spec/cql/parser/entity_types_spec.rb +0 -106
  138. data/spec/cql/parser/expressions_spec.rb +0 -199
  139. data/spec/cql/parser/fact_types_spec.rb +0 -44
  140. data/spec/cql/parser/literals_spec.rb +0 -312
  141. data/spec/cql/parser/pragmas_spec.rb +0 -89
  142. data/spec/cql/parser/value_types_spec.rb +0 -42
  143. data/spec/cql/role_matching_spec.rb +0 -148
  144. data/spec/cql/samples_spec.rb +0 -244
  145. data/spec/cql_cql_spec.rb +0 -73
  146. data/spec/cql_dm_spec.rb +0 -136
  147. data/spec/cql_mysql_spec.rb +0 -69
  148. data/spec/cql_parse_spec.rb +0 -34
  149. data/spec/cql_ruby_spec.rb +0 -73
  150. data/spec/cql_sql_spec.rb +0 -72
  151. data/spec/cql_symbol_tables_spec.rb +0 -261
  152. data/spec/cqldump_spec.rb +0 -170
  153. data/spec/helpers/array_matcher.rb +0 -23
  154. data/spec/helpers/ctrl_c_support.rb +0 -52
  155. data/spec/helpers/diff_matcher.rb +0 -39
  156. data/spec/helpers/file_matcher.rb +0 -34
  157. data/spec/helpers/parse_to_ast_matcher.rb +0 -80
  158. data/spec/helpers/string_matcher.rb +0 -30
  159. data/spec/helpers/test_parser.rb +0 -15
  160. data/spec/norma_cql_spec.rb +0 -66
  161. data/spec/norma_ruby_spec.rb +0 -62
  162. data/spec/norma_ruby_sql_spec.rb +0 -107
  163. data/spec/norma_sql_spec.rb +0 -57
  164. data/spec/norma_tables_spec.rb +0 -95
  165. data/spec/ruby_api_spec.rb +0 -23
  166. data/spec/spec_helper.rb +0 -35
  167. data/spec/transform_surrogate_spec.rb +0 -59
  168. data/status.html +0 -138
  169. data/why.html +0 -60
@@ -1,216 +0,0 @@
1
- #
2
- # ActiveFacts Generators.
3
- # Generate a Rails-friendly schema.rb from an ActiveFacts vocabulary.
4
- #
5
- # Copyright (c) 2012 Clifford Heath. Read the LICENSE file.
6
- #
7
- require 'activefacts/vocabulary'
8
- require 'activefacts/persistence'
9
- require 'activefacts/mapping/rails'
10
-
11
- module ActiveFacts
12
- module Generate
13
- module Rails
14
- # Generate a Rails-friendly schema for the vocabulary
15
- # Invoke as
16
- # afgen --rails/schema[=options] <file>.cql
17
- class SchemaRb
18
- private
19
- include Persistence
20
-
21
- def initialize(vocabulary, *options)
22
- @vocabulary = vocabulary
23
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
24
- help if options.include? "help"
25
- @exclude_fks = options.include? "exclude_fks"
26
- @include_comments = options.include? "include_comments"
27
- @closed_world = options.include? "closed_world"
28
- end
29
-
30
- def help
31
- @helping = true
32
- warn %Q{Options for --rails/schema:
33
- exclude_fks Don't generate foreign key definitions for use with Rails 4 or the foreigner gem
34
- include_comments Generate a comment for each column showing the absorption path
35
- closed_world Set this if your DBMS only allows one null in a unique index (MS SQL)
36
- }
37
- end
38
-
39
- def warn *a
40
- $stderr.puts *a
41
- end
42
-
43
- def puts s
44
- @out.puts s
45
- end
46
-
47
- public
48
-
49
- # We sort the columns here, not in the persistence layer, because it affects
50
- # the ordering of columns in an index :-(.
51
- def sorted_columns table, pk, fk_columns
52
- table.columns.sort_by do |column|
53
- [ # Emit columns alphabetically, but PK first, then FKs, then others
54
- case
55
- when i = pk.index(column)
56
- i
57
- when fk_columns.include?(column)
58
- pk.size+1
59
- else
60
- pk.size+2
61
- end,
62
- column.rails_name
63
- ]
64
- end
65
- end
66
-
67
- def generate_column table, pk, column
68
- name = column.rails_name
69
- type, params, constraints = *column.type
70
- length = params[:length]
71
- length &&= length.to_i
72
- scale = params[:scale]
73
- scale &&= scale.to_i
74
- rails_type, length = *column.rails_type
75
-
76
- length_name = rails_type == 'decimal' ? 'precision' : 'limit'
77
- length_option = length ? ", :#{length_name} => #{length}" : ''
78
- scale_option = scale ? ", :scale => #{scale}" : ''
79
-
80
- comment = column.comment
81
- null_option = ", :null => #{!column.is_mandatory}"
82
- if pk.size == 1 && pk[0] == column
83
- case rails_type
84
- when 'serial'
85
- rails_type = "primary_key"
86
- when 'uuid'
87
- rails_type = "uuid, :default => 'gen_random_uuid()', :primary_key => true"
88
- end
89
- else
90
- case rails_type
91
- when 'serial'
92
- rails_type = 'integer' # An integer foreign key
93
- end
94
- end
95
-
96
- (@include_comments ? [" \# #{comment}"] : []) +
97
- [
98
- %Q{ t.column "#{name}", :#{rails_type}#{length_option}#{scale_option}#{null_option}}
99
- ]
100
- end
101
-
102
- def generate_columns table, pk, fk_columns
103
- sc = sorted_columns(table, pk, fk_columns)
104
- lines = sc.map do |column|
105
- generate_column table, pk, column
106
- end
107
- lines.flatten
108
- end
109
-
110
- def generate_table table, foreign_keys
111
- ar_table_name = table.rails_name
112
-
113
- pk = table.identifier_columns
114
- if pk[0].is_auto_assigned
115
- identity_column = pk[0]
116
- warn "Warning: redundant column(s) after #{identity_column.name} in primary key of #{ar_table_name}" if pk.size > 1
117
- end
118
-
119
- # Get the list of references that give rise to foreign keys:
120
- fk_refs = table.references_from.select{|ref| ref.is_simple_reference }
121
-
122
- # Get the list of columns that embody the foreign keys:
123
- fk_columns = table.columns.select do |column|
124
- column.references[0].is_simple_reference
125
- end
126
-
127
- # Detect if this table is a join table.
128
- # Join tables have multi-part primary keys that are made up only of foreign keys
129
- is_join_table = pk.length > 1 and
130
- !pk.detect do |pk_column|
131
- !fk_columns.include?(pk_column)
132
- end
133
- warn "Warning: #{table.name} has a multi-part primary key" if pk.length > 1 and !is_join_table
134
-
135
- puts %Q{ create_table "#{ar_table_name}", :id => false, :force => true do |t|}
136
-
137
- columns = generate_columns table, pk, fk_columns
138
-
139
- unless @exclude_fks
140
- table.foreign_keys.each do |fk|
141
- from_columns = fk.from_columns.map{|column| column.rails_name}
142
- to_columns = fk.to_columns.map{|column| column.rails_name}
143
-
144
- foreign_keys.concat(
145
- if (from_columns.length == 1)
146
- index_name = Persistence.rails_name_trunc('index_'+fk.from.rails_name+'_on_'+from_columns[0])
147
- [
148
- " add_foreign_key :#{fk.from.rails_name}, :#{fk.to.rails_name}, :column => :#{from_columns[0]}, :primary_key => :#{to_columns[0]}, :on_delete => :cascade"
149
- ]+
150
- Array(
151
- # Index it non-uniquely only if it's not unique already:
152
- fk.jump_reference.to_role.unique ? nil :
153
- " add_index :#{fk.from.rails_name}, [:#{from_columns[0]}], :unique => false, :name => :#{index_name}"
154
- )
155
- else
156
- # This probably isn't going to work without Dr Nic's CPK gem:
157
- [
158
- " add_foreign_key :#{fk.to.rails_name}, :#{fk.from.rails_name}, :column => [:#{from_columns.join(':, ')}], :primary_key => [:#{to_columns.join(':, ')}], :on_delete => :cascade"
159
- ]
160
- end
161
- )
162
- end
163
- end
164
-
165
- indices = table.indices
166
- index_text = []
167
- indices.each do |index|
168
- next if index.is_primary && index.columns.size == 1 # We've handled this already
169
-
170
- index_name = index.rails_name
171
-
172
- unique = !index.columns.detect{|column| !column.is_mandatory} and !@closed_world
173
- index_text << %Q{ add_index "#{ar_table_name}", ["#{index.columns.map{|c| c.rails_name}*'", "'}"], :name => :#{index_name}#{
174
- unique ? ", :unique => true" : ''
175
- }}
176
- end
177
-
178
- puts columns.join("\n")
179
- puts " end\n\n"
180
-
181
- puts index_text.join("\n")
182
- puts "\n" unless index_text.empty?
183
- end
184
-
185
- def generate(out = $>) #:nodoc:
186
- return if @helping
187
- @out = out
188
-
189
- foreign_keys = []
190
-
191
- # If we get index names that need to be truncated, add a counter to ensure uniqueness
192
- dup_id = 0
193
-
194
- puts "#\n# schema.rb auto-generated using ActiveFacts for #{@vocabulary.name} on #{Date.today}\n#\n\n"
195
- puts "ActiveRecord::Base.logger = Logger.new(STDOUT)\n"
196
- puts "ActiveRecord::Schema.define(:version => #{Time.now.strftime('%Y%m%d%H%M%S')}) do"
197
- puts " enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')\n"
198
-
199
- @vocabulary.tables.each do |table|
200
- generate_table table, foreign_keys
201
- end
202
-
203
- unless @exclude_fks
204
- puts ' unless ENV["EXCLUDE_FKS"]'
205
- puts foreign_keys.join("\n")
206
- puts ' end'
207
- end
208
- puts "end"
209
- end
210
-
211
- end
212
- end
213
- end
214
- end
215
-
216
- ActiveFacts::Registry.generator('rails/schema', ActiveFacts::Generate::Rails::SchemaRb)
@@ -1,46 +0,0 @@
1
- #
2
- # ActiveFacts Generators.
3
- # Generate text output (verbalise the meta-vocabulary) for ActiveFacts vocabularies.
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- require 'activefacts/persistence'
8
-
9
- module ActiveFacts
10
- module Generate
11
- # Generate a text verbalisation of the metamodel constellation created for an ActiveFacts vocabulary.
12
- # Invoke as
13
- # afgen --text <file>.cql
14
- class RECORDS
15
- private
16
- def initialize(vocabulary)
17
- @vocabulary = vocabulary
18
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
19
- end
20
-
21
- public
22
- def generate(out = $>)
23
- # Extract the list of tables in the relational mapping of the metamodel
24
- # We'll use the columns too.
25
- @metamodel = ActiveFacts::CQL::Compiler.new.compile_file "examples/CQL/Metamodel.cql"
26
- tables = @metamodel.tables.sort_by{|t| t.name}
27
-
28
- class_names = tables.map{|t| t.name.gsub(/\s/,'')}
29
- # map{|t| ActiveFacts::Metamodel.const_get(t.name.gsub(/\s/,''))}
30
-
31
- tables.zip(class_names).each do |table, class_name|
32
- instance_index = @vocabulary.constellation.send(class_name)
33
- debugger
34
- next if instance_index.empty?
35
- out.puts "#{table.name}(#{table.columns.map{|c| c.name}*', '})"
36
- debugger
37
- instance_index.each do |key, value|
38
- out.puts "\t"+value.verbalise
39
- end
40
- end
41
- end
42
- end
43
- end
44
- end
45
-
46
- ActiveFacts::Registry.generator('records', ActiveFacts::Generate::RECORDS)
@@ -1,133 +0,0 @@
1
- #
2
- # ActiveFacts Generators.
3
- # Generate Ruby classes for the ActiveFacts API from an ActiveFacts vocabulary.
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- require 'activefacts'
8
- require 'activefacts/vocabulary'
9
- require 'activefacts/generate/helpers/oo'
10
- require 'activefacts/generate/traits/ruby'
11
- require 'activefacts/mapping/rails'
12
-
13
- module ActiveFacts
14
- module Generate
15
-
16
- # Generate Ruby module containing classes for an ActiveFacts vocabulary.
17
- # Invoke as
18
- # afgen --ruby[=options] <file>.cql
19
- # Options are comma or space separated:
20
- # * help list available options
21
- # * sql Emit the sql mapping for tables/columns (REVISIT: not functional at present)
22
- class RUBY < Helpers::OO
23
- private
24
-
25
- def set_option(option)
26
- @mapping = false
27
- case option
28
- when 'help', '?'
29
- $stderr.puts "Usage:\t\tafgen --ruby[=option,option] input_file.cql\n"+
30
- "\t\tmapping={sql|rails}\tEmit data to enable mappings to SQL or to Rails"
31
- exit 0
32
- when /mapping=(.*)/
33
- @mapping = $1
34
- @vocabulary.tables
35
- else super
36
- end
37
- end
38
-
39
- def vocabulary_start
40
- puts @vocabulary.prelude
41
- end
42
-
43
- def vocabulary_end
44
- puts @vocabulary.finale
45
- end
46
-
47
- def emit_mapping o
48
- case @mapping
49
- when 'sql'
50
- puts " table"
51
- when 'rails'
52
- puts " table :#{o.rails_name}"
53
- end
54
- end
55
-
56
- def data_type_dump(o)
57
- value_type_dump(o, o.name, {}) if o.all_role.size > 0
58
- end
59
-
60
- def value_type_dump(o, super_type_name, facets)
61
- puts o.ruby_definition
62
- end
63
-
64
- def subtype_dump(o, supertypes, pi = nil)
65
- primary_supertype = o && (o.identifying_supertype || o.supertypes[0])
66
- secondary_supertypes = o.supertypes-[primary_supertype]
67
-
68
- puts " class #{o.name.gsub(/ /,'')} < #{ primary_supertype.name.gsub(/ /,'') }"
69
- puts " identified_by #{identified_by(o, pi)}" if pi
70
- puts " supertypes "+secondary_supertypes.map{|st| st.name.gsub(/ /,'')}*", " if secondary_supertypes.size > 0
71
- emit_mapping(o) if o.is_table
72
- fact_roles_dump(o.fact_type) if o.fact_type
73
- roles_dump(o)
74
- puts " end\n\n"
75
- pi.ordered_dumped! if pi
76
- end
77
-
78
- def non_subtype_dump(o, pi)
79
- puts " class #{o.name.gsub(/ /,'')}"
80
-
81
- # We want to name the absorption role only when it's absorbed along its single identifying role.
82
- puts " identified_by #{identified_by(o, pi)}"
83
- emit_mapping o if o.is_table
84
- fact_roles_dump(o.fact_type) if o.fact_type
85
- roles_dump(o)
86
- puts " end\n\n"
87
- pi.ordered_dumped!
88
- end
89
-
90
- # Dump one fact type.
91
- def fact_type_dump(fact_type, name)
92
- return if skip_fact_type(fact_type)
93
- o = fact_type.entity_type
94
-
95
- primary_supertype = o && (o.identifying_supertype || o.supertypes[0])
96
- secondary_supertypes = o.supertypes-[primary_supertype]
97
-
98
- # Get the preferred identifier, but don't emit it unless it's different from the primary supertype's:
99
- pi = o.preferred_identifier
100
- pi = nil if pi && primary_supertype && primary_supertype.preferred_identifier == pi
101
-
102
- puts " class #{name.gsub(/ /,'')}" +
103
- (primary_supertype ? " < "+primary_supertype.name.gsub(/ /,'') : "") +
104
- "\n" +
105
- secondary_supertypes.map{|sst| " supertype :#{sst.name.gsub(/ /,'_')}"}*"\n" +
106
- (pi ? " identified_by #{identified_by(o, pi)}" : "")
107
- emit_mapping o if o.is_table
108
- fact_roles_dump(fact_type)
109
- roles_dump(o)
110
- puts " end\n\n"
111
-
112
- fact_type.ordered_dumped!
113
- end
114
-
115
- def identified_by_roles_and_facts(entity_type, identifying_role_refs, identifying_facts)
116
- identifying_role_refs.map{|role_ref|
117
- ":"+role_ref.role.preferred_role_name(entity_type)
118
- }*", "
119
- end
120
-
121
- def unary_dump(role, role_name)
122
- puts " maybe :"+role_name
123
- end
124
-
125
- def binary_dump(role, role_name, role_player, mandatory = nil, one_to_one = nil, readings = nil, counterpart_role_name = nil, counterpart_method_name = nil)
126
- puts role.as_binary(role_name, role_player, mandatory, one_to_one, readings, counterpart_role_name, counterpart_method_name)
127
- end
128
-
129
- end
130
- end
131
- end
132
-
133
- ActiveFacts::Registry.generator('ruby', ActiveFacts::Generate::RUBY)
@@ -1,280 +0,0 @@
1
- #
2
- # ActiveFacts Generators.
3
- # Generate SQL for MySQL from an ActiveFacts vocabulary.
4
- #
5
- # Copyright (c) 2009 Daniel Heath. Read the LICENSE file.
6
- #
7
- require 'activefacts/vocabulary'
8
- require 'activefacts/persistence'
9
-
10
- module ActiveFacts
11
- module Generate
12
- module SQL #:nodoc:
13
- # Generate SQL for MySQL for an ActiveFacts vocabulary.
14
- # Invoke as
15
- # afgen --sql/mysql[=options] <file>.cql
16
- # Options are comma or space separated:
17
- # * delay_fks Leave all foreign keys until the end, not just those that contain forward-references
18
- class MYSQL
19
- private
20
- include Persistence
21
- ColumnNameMax = 63
22
- DefaultCharColLength = 63
23
-
24
- RESERVED_WORDS = %w{
25
- ACCESSIBLE ADD ALL ALTER ANALYZE AND AS ASC ASENSITIVE
26
- BEFORE BETWEEN BIGINT BINARY BLOB BOTH BY CALL CASCADE
27
- CASE CHANGE CHAR CHARACTER CHECK COLLATE COLUMN CONNECTION
28
- CONDITION CONSTRAINT CONTINUE CONVERT CREATE CROSS
29
- CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER
30
- CURSOR DATABASE DATABASES DAY_HOUR DAY_MICROSECOND
31
- DAY_MINUTE DAY_SECOND DEC DECIMAL DECLARE DEFAULT DELAYED
32
- DELETE DESC DESCRIBE DETERMINISTIC DISTINCT DISTINCTROW
33
- DIV DOUBLE DROP DUAL EACH ELSE ELSEIF ENCLOSED ESCAPED
34
- EXISTS EXIT EXPLAIN FALSE FETCH FLOAT FLOAT4 FLOAT8 FOR
35
- FORCE FOREIGN FROM FULLTEXT GRANT GROUP HAVING HIGH_PRIORITY
36
- HOUR_MICROSECOND HOUR_MINUTE HOUR_SECOND IF IGNORE IN
37
- INDEX INFILE INNER INOUT INSENSITIVE INSERT INT INT1 INT2
38
- INT3 INT4 INT8 INTEGER INTERVAL INTO IS ITERATE JOIN KEY
39
- KEYS KILL LEADING LEAVE LEFT LIKE LIMIT LINEAR LINES LOAD
40
- LOCALTIME LOCALTIMESTAMP LOCK LONG LONGBLOB LONGTEXT LOOP
41
- LOW_PRIORITY MASTER_SSL_VERIFY_SERVER_CERT MATCH MEDIUMBLOB
42
- MEDIUMINT MEDIUMTEXT MIDDLEINT MINUTE_MICROSECOND
43
- MINUTE_SECOND MOD MODIFIES NATURAL NOT NO_WRITE_TO_BINLOG
44
- NULL NUMERIC ON OPTIMIZE OPTION OPTIONALLY OR ORDER OUT
45
- OUTER OUTFILE PRECISION PRIMARY PROCEDURE PURGE RANGE
46
- READ READ_ONLY READS READ_WRITE READ_WRITE REAL REFERENCES
47
- REGEXP RELEASE RENAME REPEAT REPLACE REQUIRE RESTRICT
48
- RETURN REVOKE RIGHT RLIKE SCHEMA SCHEMAS SECOND_MICROSECOND
49
- SELECT SENSITIVE SEPARATOR SET SHOW SMALLINT SPATIAL
50
- SPECIFIC SQL SQL_BIG_RESULT SQL_CALC_FOUND_ROWS SQLEXCEPTION
51
- SQL_SMALL_RESULT SQLSTATE SQLWARNING SSL STARTING
52
- STRAIGHT_JOIN TABLE TERMINATED THEN TINYBLOB TINYINT
53
- TINYTEXT TO TRAILING TRIGGER TRUE UNDO UNION UNIQUE UNLOCK
54
- UNSIGNED UPDATE UPGRADE USAGE USE USING UTC_DATE UTC_TIME
55
- UTC_TIMESTAMP VALUES VARBINARY VARCHAR VARCHARACTER VARYING
56
- WHEN WHERE WHILE WITH WRITE XOR YEAR_MONTH ZEROFILL
57
- }.inject({}){ |h,w| h[w] = true; h }
58
-
59
- def initialize(vocabulary, *options)
60
- @vocabulary = vocabulary
61
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
62
- @delay_fks = options.include? "delay_fks"
63
- end
64
-
65
- def puts s
66
- @out.puts s
67
- end
68
-
69
- def go s
70
- puts s + ";\n\n"
71
- end
72
-
73
- def escape s
74
- # Escape SQL keywords and non-identifiers
75
- s = s[0...120]
76
- if s =~ /[^A-Za-z0-9_]/ || RESERVED_WORDS[s.upcase]
77
- "`#{s}`"
78
- else
79
- s
80
- end
81
- end
82
-
83
- # Return SQL type and (modified?) length for the passed base type
84
- def normalise_type(type, length)
85
- sql_type = case type
86
- when /^Auto ?Counter$/
87
- 'int'
88
-
89
- when /^Signed ?Integer$/,
90
- /^Signed ?Small ?Integer$/
91
- s = case
92
- when length <= 8
93
- 'tinyint'
94
- when length <= 16
95
- 'shortint'
96
- when length <= 32
97
- 'int'
98
- else 'bigint'
99
- end
100
- length = nil
101
- s
102
-
103
- when /^Unsigned ?Integer$/,
104
- /^Unsigned ?Small ?Integer$/,
105
- /^Unsigned ?Tiny ?Integer$/
106
- s = case
107
- when length <= 8
108
- 'tinyint unsigned'
109
- when length <= 16
110
- 'shortint unsigned'
111
- when length <= 32
112
- 'int unsigned'
113
- else 'bigint'
114
- end
115
- length = nil
116
- s
117
-
118
- when /^Decimal$/
119
- 'decimal'
120
-
121
- when /^Fixed ?Length ?Text$/, /^Char$/
122
- length ||= DefaultCharColLength
123
- "char"
124
- when /^Variable ?Length ?Text$/, /^String$/
125
- length ||= DefaultCharColLength
126
- "varchar"
127
- # There are several large length text types; If you need to store more than 65k chars, look at using MEDIUMTEXT or LONGTEXT
128
- # CQL does not yet allow you to specify a length for LargeLengthText.
129
- when /^Large ?Length ?Text$/, /^Text$/
130
- 'text'
131
-
132
- when /^Date ?And ?Time$/, /^Date ?Time$/
133
- 'datetime'
134
- when /^Date$/
135
- 'date'
136
- when /^Time$/
137
- 'time'
138
- when /^Auto ?Time ?Stamp$/
139
- 'timestamp'
140
-
141
- when /^Money$/
142
- 'decimal'
143
- # Warning: Max 65 kbytes. To use larger types, try MediumBlob (16mb) or LongBlob (4gb)
144
- when /^Picture ?Raw ?Data$/, /^Image$/
145
- 'blob'
146
- when /^Variable ?Length ?Raw ?Data$/, /^Blob$/
147
- 'blob'
148
- # Assuming you only want a boolean out of this. Should we specify length instead?
149
- when /^BIT$/
150
- 'bit'
151
- else type # raise "SQL type unknown for standard type #{type}"
152
- end
153
- [sql_type, length]
154
- end
155
-
156
- public
157
- def generate(out = $>) #:nodoc:
158
- @out = out
159
- #go "CREATE SCHEMA #{@vocabulary.name}"
160
-
161
- tables_emitted = {}
162
- delayed_foreign_keys = []
163
-
164
- @vocabulary.tables.each do |table|
165
- puts "CREATE TABLE #{escape table.name.gsub(' ','')} ("
166
-
167
- pk = table.identifier_columns
168
- identity_column = pk[0] if pk[0].is_auto_assigned
169
-
170
- fk_refs = table.references_from.select{|ref| ref.is_simple_reference }
171
- fk_columns = table.columns.select do |column|
172
- column.references[0].is_simple_reference
173
- end
174
-
175
- # We sort the columns here, not in the persistence layer, because it affects
176
- # the ordering of columns in an index :-(.
177
- columns = table.columns.sort_by { |column| column.name(nil) }.map do |column|
178
- name = escape column.name("")
179
- padding = " "*(name.size >= ColumnNameMax ? 1 : ColumnNameMax-name.size)
180
- type, params, constraints = column.type
181
- constraints = [] if (fk_columns.include?(column)) # Don't enforce VT constraints on FK columns
182
- length = params[:length]
183
- length &&= length.to_i
184
- scale = params[:scale]
185
- scale &&= scale.to_i
186
- type, length = normalise_type(type, length)
187
- sql_type = "#{type}#{
188
- if !length
189
- ""
190
- else
191
- "(" + length.to_s + (scale ? ", #{scale}" : "") + ")"
192
- end
193
- }"
194
- identity = column == identity_column ? " AUTO_INCREMENT" : ""
195
- null = (column.is_mandatory ? "NOT " : "") + "NULL"
196
- check = check_clause(name, constraints)
197
- comment = column.comment
198
- [ "-- #{comment}", "#{name}#{padding}#{sql_type}#{identity} #{null}#{check}" ]
199
- end.flatten
200
-
201
- pk_def = (pk.detect{|column| !column.is_mandatory} ? "UNIQUE(" : "PRIMARY KEY(") +
202
- pk.map{|column| escape column.name("")}*", " +
203
- ")"
204
-
205
- inline_fks = []
206
- table.foreign_keys.each do |fk|
207
- fk_text = "FOREIGN KEY (" +
208
- fk.from_columns.map{|column| column.name}*", " +
209
- ") REFERENCES #{escape fk.to.name.gsub(' ','')} (" +
210
- fk.to_columns.map{|column| column.name}*", " +
211
- ")"
212
- if !@delay_fks and # We don't want to delay all Fks
213
- (tables_emitted[fk.to] or # The target table has been emitted
214
- fk.to == table && !fk.to_columns.detect{|column| !column.is_mandatory}) # The reference columns already have the required indexes
215
- inline_fks << fk_text
216
- else
217
- delayed_foreign_keys << ("ALTER TABLE #{escape fk.from.name.gsub(' ','')}\n\tADD " + fk_text)
218
- end
219
- end
220
-
221
- indices = table.indices
222
- inline_indices = []
223
- delayed_indices = []
224
- indices.each do |index|
225
- next if index.over == table && index.is_primary # Already did the primary keys
226
- abbreviated_column_names = index.abbreviated_column_names*""
227
- column_names = index.column_names
228
- column_name_list = column_names.map{|n| escape(n)}*", "
229
- inline_indices << "UNIQUE(#{column_name_list})"
230
- end
231
-
232
- tables_emitted[table] = true
233
-
234
- puts("\t" + (columns + [pk_def] + inline_indices + inline_fks)*",\n\t")
235
- go ")"
236
- delayed_indices.each {|index_text|
237
- go index_text
238
- }
239
- end
240
-
241
- delayed_foreign_keys.each do |fk|
242
- go fk
243
- end
244
- end
245
-
246
- private
247
- def sql_value(value)
248
- value.is_literal_string ? sql_string(value.literal) : value.literal
249
- end
250
-
251
- def sql_string(str)
252
- "'" + str.gsub(/'/,"''") + "'"
253
- end
254
-
255
- def check_clause(column_name, constraints)
256
- return "" if constraints.empty?
257
- # REVISIT: Merge all constraints (later; now just use the first)
258
- " CHECK(" +
259
- constraints[0].all_allowed_range_sorted.map do |ar|
260
- vr = ar.value_range
261
- min = vr.minimum_bound
262
- max = vr.maximum_bound
263
- if (min && max && max.value.literal == min.value.literal)
264
- "#{column_name} = #{sql_value(min.value)}"
265
- else
266
- inequalities = [
267
- min && "#{column_name} >#{min.is_inclusive ? "=" : ""} #{sql_value(min.value)}",
268
- max && "#{column_name} <#{max.is_inclusive ? "=" : ""} #{sql_value(max.value)}"
269
- ].compact
270
- inequalities.size > 1 ? "(" + inequalities*" AND " + ")" : inequalities[0]
271
- end
272
- end*" OR " +
273
- ")"
274
- end
275
- end
276
- end
277
- end
278
- end
279
-
280
- ActiveFacts::Registry.generator('sql/mysql', ActiveFacts::Generate::SQL::MYSQL)