activefacts 1.6.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
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)