activefacts-compositions 1.9.17 → 1.9.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/activefacts-compositions.gemspec +2 -2
  3. data/lib/activefacts/compositions/binary.rb +1 -1
  4. data/lib/activefacts/compositions/compositor.rb +16 -12
  5. data/lib/activefacts/compositions/datavault.rb +110 -115
  6. data/lib/activefacts/compositions/relational.rb +137 -94
  7. data/lib/activefacts/compositions/staging.rb +89 -27
  8. data/lib/activefacts/compositions/traits/datavault.rb +116 -49
  9. data/lib/activefacts/compositions/traits/rails.rb +2 -2
  10. data/lib/activefacts/compositions/version.rb +1 -1
  11. data/lib/activefacts/generator/doc/cwm.rb +6 -18
  12. data/lib/activefacts/generator/doc/ldm.rb +1 -1
  13. data/lib/activefacts/generator/etl/unidex.rb +341 -0
  14. data/lib/activefacts/generator/oo.rb +31 -14
  15. data/lib/activefacts/generator/rails/models.rb +6 -5
  16. data/lib/activefacts/generator/rails/schema.rb +5 -9
  17. data/lib/activefacts/generator/ruby.rb +2 -2
  18. data/lib/activefacts/generator/sql/mysql.rb +3 -184
  19. data/lib/activefacts/generator/sql/oracle.rb +3 -152
  20. data/lib/activefacts/generator/sql/postgres.rb +3 -145
  21. data/lib/activefacts/generator/sql/server.rb +3 -126
  22. data/lib/activefacts/generator/sql.rb +54 -422
  23. data/lib/activefacts/generator/summary.rb +15 -6
  24. data/lib/activefacts/generator/traits/expr.rb +41 -0
  25. data/lib/activefacts/generator/traits/sql/mysql.rb +280 -0
  26. data/lib/activefacts/generator/traits/sql/oracle.rb +265 -0
  27. data/lib/activefacts/generator/traits/sql/postgres.rb +287 -0
  28. data/lib/activefacts/generator/traits/sql/server.rb +262 -0
  29. data/lib/activefacts/generator/traits/sql.rb +538 -0
  30. metadata +13 -8
  31. data/lib/activefacts/compositions/docgraph.rb +0 -798
  32. data/lib/activefacts/compositions/staging/persistent.rb +0 -107
@@ -0,0 +1,538 @@
1
+ #
2
+ # ActiveFacts Standard SQL Traits
3
+ #
4
+ # Copyright (c) 2009-2016 Clifford Heath. Read the LICENSE file.
5
+ #
6
+ # Reserved words for various versions of the standard gathered from:
7
+ # http://developer.mimer.se/validator/sql-reserved-words.tml
8
+ # https://www.postgresql.org/docs/9.5/static/sql-keywords-appendix.html
9
+ #
10
+ require 'digest/sha1'
11
+ require 'activefacts/metamodel'
12
+ require 'activefacts/metamodel/datatypes'
13
+ require 'activefacts/compositions'
14
+ require 'activefacts/compositions/names'
15
+ require 'activefacts/generator'
16
+ require 'activefacts/generator/traits/expr'
17
+
18
+ module ActiveFacts
19
+ module Generators
20
+ module Traits
21
+ module SQL
22
+ MM = ActiveFacts::Metamodel unless const_defined?(:MM)
23
+
24
+ # Options available in this flavour of SQL
25
+ def options
26
+ {
27
+ keywords: ['Boolean', "Quote all keywords, not just reserved words"],
28
+ restrict: ['String', "Restrict generation to tables in the specified group (e.g. bdv, rdv)"],
29
+ joiner: ['String', "Use 'str' instead of the default joiner between words in table and column names"],
30
+ unicode: ['Boolean', "Use Unicode for all text fields by default"],
31
+ tables: [%w{cap title camel snake shout}, "Case to use for table names"],
32
+ columns: [%w{cap title camel snake shout}, "Case to use for table names"],
33
+ surrogates: [%w{counter guid hash}, "Method to use for assigning surrogate keys"],
34
+ fks: [%w{no yes delay}, "Emit foreign keys, delay them to the end, or omit them"],
35
+ # Legacy: datavault: ['String', "Generate 'raw' or 'business' data vault tables"],
36
+ }
37
+ end
38
+
39
+ # The options parameter overrides any default options set by sub-traits
40
+ def defaults_and_options options
41
+ options
42
+ end
43
+
44
+ def process_options options
45
+ @options = defaults_and_options options
46
+
47
+ @quote_keywords = {nil=>true, 't'=>true, 'f'=>false, 'y'=>true, 'n'=>false}[@options.delete 'keywords']
48
+ @quote_keywords = false if @keywords == nil # Set default
49
+ case (@options.delete "fks" || true)
50
+ when true, '', 't', 'y', 'yes'
51
+ @fks = true
52
+ when 'd', 'delay'
53
+ @fks = true
54
+ @delay_fks = true
55
+ when false, 'f', 'n', 'no'
56
+ @fks = false
57
+ end
58
+ @unicode = @options.delete "unicode"
59
+ @restrict = @options.delete "restrict"
60
+ @surrogate_method = @options.delete('surrogates') || 'counter'
61
+ raise "Unknown surrogate assignment method" unless %w{counter guid hash}.include?(@surrogate_method)
62
+
63
+ # Name configuration options:
64
+ @joiner = @options.delete('joiner')
65
+ @table_joiner = @options.has_key?('tables') ? @joiner : nil
66
+ @table_case = ((@options.delete('tables') || 'cap') + 'words').to_sym
67
+ @table_joiner ||= [:snakewords, :shoutwords].include?(@table_case) ? '_' : ''
68
+ @column_joiner = @options.has_key?('columns') ? @joiner : nil
69
+ @column_case = ((@options.delete('columns') || 'cap') + 'words').to_sym
70
+ @column_joiner ||= [:snakewords, :shoutwords].include?(@column_case) ? '_' : ''
71
+
72
+ # Legacy option. Use restrict=bdv/rdv instead
73
+ @datavault = @options.delete "datavault"
74
+ case @datavault
75
+ when "business"
76
+ @restrict = "bdv"
77
+ when "raw"
78
+ @restrict = "rdv"
79
+ end
80
+
81
+ # Do not (yet) expose the closed-world vs open world problem.
82
+ # Closed World vs Open World uniqueness is a semantic issue,
83
+ # and so is OW, CW or CW with negation for unary fact types.
84
+ # We need an overall strategy for handling it.
85
+ @closed_world_indices = false # Allow for SQL Server's non-standard NULL indexing
86
+ end
87
+
88
+ def data_type_context
89
+ @data_type_context ||= data_type_context_class.new(surrogate_method: @surrogate_method)
90
+ end
91
+
92
+ def data_type_context_class
93
+ SQLDataTypeContext
94
+ end
95
+
96
+ def table_name_max
97
+ 1024
98
+ end
99
+
100
+ def column_name_max
101
+ 1024
102
+ end
103
+
104
+ def index_name_max
105
+ 1024
106
+ end
107
+
108
+ def schema_name_max
109
+ 1024
110
+ end
111
+
112
+ # Anything this flavour needs to prefix a schema:
113
+ def schema_prefix
114
+ ''
115
+ end
116
+
117
+ def index_kind(index)
118
+ ''
119
+ end
120
+
121
+ def binary_surrogate(type_name, value_constraint, options)
122
+ if options[:auto_assign] == 'hash'
123
+ :hash
124
+ elsif type_name =~ /^(guid|uuid)$/i
125
+ options[:length] ||= 16
126
+ if ![nil, ''].include?(options[:auto_assign])
127
+ options.delete(:auto_assign) # Don't auto-assign foreign keys
128
+ :guid
129
+ else
130
+ :guid_fk
131
+ end
132
+ else
133
+ false
134
+ end
135
+ end
136
+
137
+ # Return SQL type and (modified?) length for the passed base type
138
+ def choose_sql_type(type_name, value_constraint, component, options)
139
+ case MM::DataType.intrinsic_type(type_name)
140
+ when MM::DataType::TYPE_Boolean
141
+ data_type_context.boolean_type
142
+
143
+ when MM::DataType::TYPE_Integer
144
+ # The :auto_assign key is set for auto-assigned types, but with a nil value in foreign keys
145
+ length = options[:length]
146
+ if options.has_key?(:auto_assign)
147
+ options[:default] ||= ' GENERATED ALWAYS AS IDENTITY' if options[:auto_assign]
148
+ length = data_type_context.default_autoincrement_length
149
+ type_name = 'int'
150
+ end
151
+ if chosen = MM::DataType.choose_integer(type_name, length, value_constraint, data_type_context)
152
+ options.delete(:length)
153
+ chosen
154
+ else # No available integer seems to suit. Use the defined type and length
155
+ type_name
156
+ end
157
+
158
+ when MM::DataType::TYPE_Real
159
+ 'FLOAT'
160
+
161
+ when MM::DataType::TYPE_Decimal
162
+ 'DECIMAL'
163
+
164
+ when MM::DataType::TYPE_Money
165
+ 'DECIMAL'
166
+
167
+ when MM::DataType::TYPE_Char
168
+ data_type_context.default_char_type
169
+
170
+ when MM::DataType::TYPE_String
171
+ data_type_context.default_varchar_type
172
+
173
+ when MM::DataType::TYPE_Text
174
+ options[:length] ||= 'MAX'
175
+ data_type_context.default_text_type
176
+
177
+ when MM::DataType::TYPE_Date
178
+ 'DATE'
179
+
180
+ when MM::DataType::TYPE_Time
181
+ 'TIME'
182
+
183
+ when MM::DataType::TYPE_DateTime
184
+ 'TIMESTAMP'
185
+
186
+ when MM::DataType::TYPE_Timestamp
187
+ 'TIMESTAMP'
188
+
189
+ when MM::DataType::TYPE_Binary
190
+ # If it's a surrogate, that might change the length we use
191
+ binary_surrogate(type_name, value_constraint, options)
192
+ if options[:length]
193
+ 'BINARY' # Fixed length
194
+ else
195
+ 'VARBINARY'
196
+ end
197
+ else
198
+ type_name
199
+ end
200
+ end
201
+
202
+ # The Components passed as leaves are fields in a table.
203
+ # Return an array of SQL field names.
204
+ def safe_column_names leaves
205
+ leaves.map &method(:safe_column_name)
206
+ end
207
+
208
+ # Return an Expression for the Component passed as leaf, optionally using a table or alias name
209
+ def safe_column_expr leaf, table_prefix = ''
210
+ column_name = safe_column_name(leaf)
211
+ type_name, = leaf.data_type(data_type_context)
212
+ type_num = MM::DataType.intrinsic_type(type_name)
213
+ Expression.new(table_prefix+column_name, type_num, leaf.is_mandatory)
214
+ end
215
+
216
+ # Return an array of Expressions for the fields, optionally qualified with a table or alias name
217
+ def safe_column_exprs leaves, use_table_name = nil
218
+ leaves.map{|leaf| safe_column_expr(leaf, table_prefix(leaf, use_table_name))}
219
+ end
220
+
221
+ # Return the string to prefix a column expression with to qualify it with a table or alias name
222
+ def table_prefix component, use_table_name = nil
223
+ case use_table_name
224
+ when false, nil
225
+ ''
226
+ when true
227
+ safe_table_name(component)+'.'
228
+ else
229
+ use_table_name+'.'
230
+ end
231
+ end
232
+
233
+ def create_or_replace(name, kind)
234
+ # There's no standard SQL way to do this. Do it anyway.
235
+ "CREATE OR REPLACE #{kind} #{name}"
236
+ end
237
+
238
+ # For an (array of) Expression, return expressions that have value "na" if NULL
239
+ def coalesce exprs, na = "'NA'"
240
+ return exprs.map{|expr| coalesce(expr)} if Array === exprs
241
+ return exprs if exprs.is_mandatory
242
+ Expression.new("COALESCE(#{exprs}, #{na})", exprs.type_num, true)
243
+ end
244
+
245
+ def reserved_words
246
+ @reserved_words ||= %w{
247
+ ABS ABSOLUTE ACTION ADD ALL ALLOCATE ALTER AND ANY ARE
248
+ ARRAY ARRAY_AGG ARRAY_MAX_CARDINALITY AS ASC ASENSITIVE
249
+ ASSERTION ASYMMETRIC AT ATOMIC AUTHORIZATION AVG BEGIN
250
+ BEGIN_FRAME BEGIN_PARTITION BETWEEN BIGINT BINARY BIT
251
+ BIT_LENGTH BLOB BOOLEAN BOTH BY CALL CALLED CARDINALITY
252
+ CASCADE CASCADED CASE CAST CATALOG CEIL CEILING CHAR
253
+ CHARACTER CHARACTER_LENGTH CHAR_LENGTH CHECK CLOB CLOSE
254
+ COALESCE COLLATE COLLATION COLLECT COLUMN COMMIT CONDITION
255
+ CONNECT CONNECTION CONSTRAINT CONSTRAINTS CONTAINS CONTINUE
256
+ CONVERT CORR CORRESPONDING COUNT COVAR_POP COVAR_SAMP
257
+ CREATE CROSS CUBE CUME_DIST CURRENT CURRENT_CATALOG
258
+ CURRENT_DATE CURRENT_DEFAULT_TRANSFORM_GROUP CURRENT_PATH
259
+ CURRENT_ROLE CURRENT_ROW CURRENT_SCHEMA CURRENT_TIME
260
+ CURRENT_TIMESTAMP CURRENT_TRANSFORM_GROUP_FOR_TYPE
261
+ CURRENT_USER CURSOR CYCLE DATALINK DATE DAY DEALLOCATE
262
+ DEC DECIMAL DECLARE DEFAULT DEFERRABLE DEFERRED DELETE
263
+ DENSE_RANK DEREF DESC DESCRIBE DESCRIPTOR DETERMINISTIC
264
+ DIAGNOSTICS DISCONNECT DISTINCT DLNEWCOPY DLPREVIOUSCOPY
265
+ DLURLCOMPLETE DLURLCOMPLETEONLY DLURLCOMPLETEWRITE DLURLPATH
266
+ DLURLPATHONLY DLURLPATHWRITE DLURLSCHEME DLURLSERVER
267
+ DLVALUE DO DOMAIN DOUBLE DROP DYNAMIC EACH ELEMENT ELSE
268
+ ELSEIF END END-EXEC END_FRAME END_PARTITION EQUALS ESCAPE
269
+ EVERY EXCEPT EXCEPTION EXEC EXECUTE EXISTS EXIT EXP
270
+ EXTERNAL EXTRACT FALSE FETCH FILTER FIRST FIRST_VALUE
271
+ FLOAT FLOOR FOR FOREIGN FOUND FRAME_ROW FREE FROM FULL
272
+ FUNCTION FUSION GET GLOBAL GO GOTO GRANT GROUP GROUPING
273
+ GROUPS HANDLER HAVING HOLD HOUR IDENTITY IF IMMEDIATE
274
+ IMPORT IN INDICATOR INITIALLY INNER INOUT INPUT INSENSITIVE
275
+ INSERT INT INTEGER INTERSECT INTERSECTION INTERVAL INTO
276
+ IS ISOLATION ITERATE JOIN KEY LAG LANGUAGE LARGE LAST
277
+ LAST_VALUE LATERAL LEAD LEADING LEAVE LEFT LEVEL LIKE
278
+ LIKE_REGEX LN LOCAL LOCALTIME LOCALTIMESTAMP LOOP LOWER
279
+ MATCH MAX MAX_CARDINALITY MEMBER MERGE METHOD MIN MINUTE
280
+ MOD MODIFIES MODULE MONTH MULTISET NAMES NATIONAL NATURAL
281
+ NCHAR NCLOB NEW NEXT NO NONE NORMALIZE NOT NTH_VALUE NTILE
282
+ NULL NULLIF NUMERIC OCCURRENCES_REGEX OCTET_LENGTH OF
283
+ OFFSET OLD ON ONLY OPEN OPTION OR ORDER OUT OUTER OUTPUT
284
+ OVER OVERLAPS OVERLAY PAD PARAMETER PARTIAL PARTITION
285
+ PERCENT PERCENTILE_CONT PERCENTILE_DISC PERCENT_RANK
286
+ PERIOD PORTION POSITION POSITION_REGEX POWER PRECEDES
287
+ PRECISION PREPARE PRESERVE PRIMARY PRIOR PRIVILEGES
288
+ PROCEDURE PUBLIC RANGE RANK READ READS REAL RECURSIVE REF
289
+ REFERENCES REFERENCING REGR_AVGX REGR_AVGY REGR_COUNT
290
+ REGR_INTERCEPT REGR_R2 REGR_SLOPE REGR_SXX REGR_SXY
291
+ REGR_SYY RELATIVE RELEASE REPEAT RESIGNAL RESTRICT RESULT
292
+ RETURN RETURNS REVOKE RIGHT ROLLBACK ROLLUP ROW ROWS
293
+ ROW_NUMBER SAVEPOINT SCHEMA SCOPE SCROLL SEARCH SECOND
294
+ SECTION SELECT SENSITIVE SESSION SESSION_USER SET SIGNAL
295
+ SIMILAR SIZE SMALLINT SOME SPACE SPECIFIC SPECIFICTYPE
296
+ SQL SQLCODE SQLERROR SQLEXCEPTION SQLSTATE SQLWARNING
297
+ SQRT START STATIC STDDEV_POP STDDEV_SAMP SUBMULTISET
298
+ SUBSTRING SUBSTRING_REGEX SUCCEEDS SUM SYMMETRIC SYSTEM
299
+ SYSTEM_TIME SYSTEM_USER TABLE TABLESAMPLE TEMPORARY THEN
300
+ TIME TIMESTAMP TIMEZONE_HOUR TIMEZONE_MINUTE TO TRAILING
301
+ TRANSACTION TRANSLATE TRANSLATE_REGEX TRANSLATION TREAT
302
+ TRIGGER TRIM TRIM_ARRAY TRUE TRUNCATE UESCAPE UNDO UNION
303
+ UNIQUE UNKNOWN UNNEST UNTIL UPDATE UPPER USAGE USER USING
304
+ VALUE VALUES VALUE_OF VARBINARY VARCHAR VARYING VAR_POP
305
+ VAR_SAMP VERSIONING VIEW WHEN WHENEVER WHERE WHILE
306
+ WIDTH_BUCKET WINDOW WITH WITHIN WITHOUT WORK WRITE XML
307
+ XMLAGG XMLATTRIBUTES XMLBINARY XMLCAST XMLCOMMENT XMLCONCAT
308
+ XMLDOCUMENT XMLELEMENT XMLEXISTS XMLFOREST XMLITERATE
309
+ XMLNAMESPACES XMLPARSE XMLPI XMLQUERY XMLSERIALIZE XMLTABLE
310
+ XMLTEXT XMLVALIDATE YEAR ZONE
311
+ }
312
+ end
313
+
314
+ def key_words
315
+ @key_words ||= %w{
316
+ A ABSENT ACCORDING ADA ADMIN AFTER ALWAYS ASSIGNMENT
317
+ ATTRIBUTE ATTRIBUTES BASE64 BEFORE BERNOULLI BLOCKED BOM
318
+ BREADTH C CATALOG_NAME CHAIN CHARACTERISTICS CHARACTERS
319
+ CHARACTER_SET_CATALOG CHARACTER_SET_NAME CHARACTER_SET_SCHEMA
320
+ CLASS_ORIGIN COBOL COLLATION_CATALOG COLLATION_NAME
321
+ COLLATION_SCHEMA COLUMNS COLUMN_NAME COMMAND_FUNCTION
322
+ COMMAND_FUNCTION_CODE COMMITTED CONDITION_NUMBER
323
+ CONNECTION_NAME CONSTRAINT_CATALOG CONSTRAINT_NAME
324
+ CONSTRAINT_SCHEMA CONSTRUCTOR CONTENT CONTROL CURSOR_NAME
325
+ DATA DATETIME_INTERVAL_CODE DATETIME_INTERVAL_PRECISION
326
+ DB DEFAULTS DEFINED DEFINER DEGREE DEPTH DERIVED DISPATCH
327
+ DOCUMENT DYNAMIC_FUNCTION DYNAMIC_FUNCTION_CODE EMPTY
328
+ ENCODING ENFORCED EXCLUDE EXCLUDING EXPRESSION FILE FINAL
329
+ FLAG FOLLOWING FORTRAN FS G GENERAL GENERATED GRANTED HEX
330
+ HIERARCHY ID IGNORE IMMEDIATELY IMPLEMENTATION INCLUDING
331
+ INCREMENT INDENT INSTANCE INSTANTIABLE INSTEAD INTEGRITY
332
+ INVOKER K KEY_MEMBER KEY_TYPE LENGTH LIBRARY LIMIT LINK
333
+ LOCATION LOCATOR M MAP MAPPING MATCHED MAXVALUE MESSAGE_LENGTH
334
+ MESSAGE_OCTET_LENGTH MESSAGE_TEXT MINVALUE MORE MUMPS
335
+ NAME NAMESPACE NESTING NFC NFD NFKC NFKD NIL NORMALIZED
336
+ NULLABLE NULLS NUMBER OBJECT OCTETS OFF OPTIONS ORDERING
337
+ ORDINALITY OTHERS OVERRIDING P PARAMETER_MODE PARAMETER_NAME
338
+ PARAMETER_ORDINAL_POSITION PARAMETER_SPECIFIC_CATALOG
339
+ PARAMETER_SPECIFIC_NAME PARAMETER_SPECIFIC_SCHEMA PASCAL
340
+ PASSING PASSTHROUGH PATH PERMISSION PLACING PLI PRECEDING
341
+ RECOVERY REPEATABLE REQUIRING RESPECT RESTART RESTORE
342
+ RETURNED_CARDINALITY RETURNED_LENGTH RETURNED_OCTET_LENGTH
343
+ RETURNED_SQLSTATE RETURNING ROLE ROUTINE ROUTINE_CATALOG
344
+ ROUTINE_NAME ROUTINE_SCHEMA ROW_COUNT SCALE SCHEMA_NAME
345
+ SCOPE_CATALOG SCOPE_NAME SCOPE_SCHEMA SECURITY SELECTIVE
346
+ SELF SEQUENCE SERIALIZABLE SERVER SERVER_NAME SETS SIMPLE
347
+ SOURCE SPECIFIC_NAME STANDALONE STATE STATEMENT STRIP
348
+ STRUCTURE STYLE SUBCLASS_ORIGIN T TABLE_NAME TIES TOKEN
349
+ TOP_LEVEL_COUNT TRANSACTIONS_COMMITTED TRANSACTIONS_ROLLED_BACK
350
+ TRANSACTION_ACTIVE TRANSFORM TRANSFORMS TRIGGER_CATALOG
351
+ TRIGGER_NAME TRIGGER_SCHEMA TYPE UNBOUNDED UNCOMMITTED
352
+ UNDER UNLINK UNNAMED UNTYPED URI USER_DEFINED_TYPE_CATALOG
353
+ USER_DEFINED_TYPE_CODE USER_DEFINED_TYPE_NAME
354
+ USER_DEFINED_TYPE_SCHEMA VALID VERSION WHITESPACE WRAPPER
355
+ XMLDECLARATION XMLSCHEMA YES
356
+ }
357
+ end
358
+
359
+ def is_reserved_word w
360
+ @reserved_word_hash ||=
361
+ ( reserved_words +
362
+ (@quote_keywords ? key_words : [])).
363
+ inject({}) do |h,w|
364
+ h[w] = true
365
+ h
366
+ end
367
+ @reserved_word_hash[w.upcase]
368
+ end
369
+
370
+ def go s = ''
371
+ "#{s.sub(/\A\n+/,'')};\n"
372
+ end
373
+
374
+ def sql_value(value)
375
+ value.is_literal_string ? sql_string(value.literal) : value.literal
376
+ end
377
+
378
+ def sql_string(str)
379
+ "'" + str.gsub(/'/,"''") + "'"
380
+ end
381
+
382
+ def open_escape
383
+ '"'
384
+ end
385
+
386
+ def close_escape
387
+ '"'
388
+ end
389
+
390
+ def escape s, max = table_name_max
391
+ # Escape SQL keywords and non-identifiers
392
+ if s.size > max
393
+ excess = s[max..-1]
394
+ s = s[0...max-(excess.size/8)] +
395
+ Digest::SHA1.hexdigest(excess)[0...excess.size/8]
396
+ end
397
+
398
+ if s =~ /[^A-Za-z0-9_]/ || is_reserved_word(s)
399
+ "#{open_escape}#{s}#{close_escape}"
400
+ else
401
+ s
402
+ end
403
+ end
404
+
405
+ def safe_table_name composite
406
+ escape(table_name(composite), table_name_max)
407
+ end
408
+
409
+ def safe_column_name component
410
+ escape(column_name(component), column_name_max)
411
+ end
412
+
413
+ def schema_name composition = @composition
414
+ composition.name.words.send(@table_case)*@table_joiner
415
+ end
416
+
417
+ def table_name composite
418
+ composite.mapping.name.words.send(@table_case)*@table_joiner
419
+ end
420
+
421
+ def column_name component
422
+ words = component.column_name.send(@column_case)
423
+ words*@column_joiner
424
+ end
425
+
426
+ def check_clause column_name, value_constraint
427
+ " CHECK(" +
428
+ value_constraint.all_allowed_range_sorted.map do |ar|
429
+ vr = ar.value_range
430
+ min = vr.minimum_bound
431
+ max = vr.maximum_bound
432
+ if (min && max && max.value.literal == min.value.literal)
433
+ "#{column_name} = #{sql_value(min.value)}"
434
+ else
435
+ inequalities = [
436
+ min && "#{column_name} >#{min.is_inclusive ? "=" : ""} #{sql_value(min.value)}",
437
+ max && "#{column_name} <#{max.is_inclusive ? "=" : ""} #{sql_value(max.value)}"
438
+ ].compact
439
+ inequalities.size > 1 ? "(" + inequalities*" AND " + ")" : inequalities[0]
440
+ end
441
+ end*" OR " +
442
+ ")"
443
+ end
444
+
445
+ class SQLDataTypeContext < MM::DataType::Context
446
+ def initialize options = {}
447
+ @surrogate_method = options.delete(:surrogate_method) || "counter"
448
+ super
449
+ end
450
+
451
+ def integer_ranges
452
+ [
453
+ ['SMALLINT', -2**15, 2**15-1], # The standard says -10^5..10^5 (less than 16 bits)
454
+ ['INTEGER', -2**31, 2**31-1], # The standard says -10^10..10^10 (more than 32 bits!)
455
+ ['BIGINT', -2**63, 2**63-1], # The standard says -10^19..10^19 (less than 64 bits)
456
+ ]
457
+ end
458
+
459
+ def default_length data_type, type_name
460
+ case data_type
461
+ when MM::DataType::TYPE_Real
462
+ 53 # IEEE Double precision floating point
463
+ when MM::DataType::TYPE_Integer
464
+ case type_name
465
+ when /([a-z ]|\b)Tiny([a-z ]|\b)/i
466
+ 8
467
+ when /([a-z ]|\b)Small([a-z ]|\b)/i,
468
+ /([a-z ]|\b)Short([a-z ]|\b)/i
469
+ 16
470
+ when /([a-z ]|\b)Big(INT)?([a-z ]|\b)/i
471
+ 64
472
+ else
473
+ 32
474
+ end
475
+ else
476
+ nil
477
+ end
478
+ end
479
+
480
+ # Note that BOOLEAN is an optional data type in SQL99.
481
+ # Official literals are TRUE, FALSE and UNKNOWN.
482
+ # Almost nothing (except Postgres) implements BOOLEAN, and
483
+ # even that doesn't implement UNKNOWN (which works like NULL)
484
+ def boolean_type
485
+ 'BOOLEAN'
486
+ end
487
+
488
+ # safe_column_name is an expression which yields boolean_type.
489
+ # We use boolean_expr when we want to use it in a conditional context.
490
+ def boolean_expr safe_column_name
491
+ safe_column_name
492
+ end
493
+
494
+ def hash_type
495
+ ['BINARY', {length: 32, auto_assign: 'hash' }]
496
+ end
497
+
498
+ # What type to use for a Metamodel::SurrogateKey
499
+ def surrogate_type
500
+ case @surrogate_method
501
+ when 'guid'
502
+ ["GUID", {auto_assign: 'guid'}]
503
+ when 'hash'
504
+ hash_type
505
+ else # counter
506
+ type_name, min, max, length = choose_integer_range(0, 2**(default_autoincrement_length-1)-1)
507
+ type_name
508
+ end
509
+ end
510
+
511
+ def date_time_type
512
+ 'TIMESTAMP'
513
+ end
514
+
515
+ def default_char_type
516
+ (@unicode ? 'NATIONAL ' : '') +
517
+ 'CHARACTER'
518
+ end
519
+
520
+ def default_varchar_type
521
+ (@unicode ? 'NATIONAL ' : '') +
522
+ 'VARCHAR'
523
+ end
524
+
525
+ # Number of bits in an auto-counter
526
+ def default_autoincrement_length
527
+ 64
528
+ end
529
+
530
+ def default_text_type
531
+ default_varchar_type
532
+ end
533
+ end
534
+
535
+ end
536
+ end
537
+ end
538
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activefacts-compositions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.17
4
+ version: 1.9.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clifford Heath
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-15 00:00:00.000000000 Z
11
+ date: 2018-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -149,7 +149,7 @@ dependencies:
149
149
  version: '1'
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
- version: 1.9.20
152
+ version: 1.9.22
153
153
  type: :runtime
154
154
  prerelease: false
155
155
  version_requirements: !ruby/object:Gem::Requirement
@@ -159,7 +159,7 @@ dependencies:
159
159
  version: '1'
160
160
  - - ">="
161
161
  - !ruby/object:Gem::Version
162
- version: 1.9.20
162
+ version: 1.9.22
163
163
  - !ruby/object:Gem::Dependency
164
164
  name: activefacts-cql
165
165
  requirement: !ruby/object:Gem::Requirement
@@ -169,7 +169,7 @@ dependencies:
169
169
  version: '1'
170
170
  - - ">="
171
171
  - !ruby/object:Gem::Version
172
- version: 1.9.3
172
+ version: 1.9.5
173
173
  type: :runtime
174
174
  prerelease: false
175
175
  version_requirements: !ruby/object:Gem::Requirement
@@ -179,7 +179,7 @@ dependencies:
179
179
  version: '1'
180
180
  - - ">="
181
181
  - !ruby/object:Gem::Version
182
- version: 1.9.3
182
+ version: 1.9.5
183
183
  description: Create and represent composite schemas, schema transforms and data transforms
184
184
  over a fact-based model
185
185
  email:
@@ -205,11 +205,9 @@ files:
205
205
  - lib/activefacts/compositions/compositor.rb
206
206
  - lib/activefacts/compositions/constraints.rb
207
207
  - lib/activefacts/compositions/datavault.rb
208
- - lib/activefacts/compositions/docgraph.rb
209
208
  - lib/activefacts/compositions/names.rb
210
209
  - lib/activefacts/compositions/relational.rb
211
210
  - lib/activefacts/compositions/staging.rb
212
- - lib/activefacts/compositions/staging/persistent.rb
213
211
  - lib/activefacts/compositions/traits/datavault.rb
214
212
  - lib/activefacts/compositions/traits/rails.rb
215
213
  - lib/activefacts/compositions/version.rb
@@ -219,6 +217,7 @@ files:
219
217
  - lib/activefacts/generator/doc/glossary.rb
220
218
  - lib/activefacts/generator/doc/graphviz.rb
221
219
  - lib/activefacts/generator/doc/ldm.rb
220
+ - lib/activefacts/generator/etl/unidex.rb
222
221
  - lib/activefacts/generator/oo.rb
223
222
  - lib/activefacts/generator/rails/models.rb
224
223
  - lib/activefacts/generator/rails/schema.rb
@@ -229,6 +228,12 @@ files:
229
228
  - lib/activefacts/generator/sql/postgres.rb
230
229
  - lib/activefacts/generator/sql/server.rb
231
230
  - lib/activefacts/generator/summary.rb
231
+ - lib/activefacts/generator/traits/expr.rb
232
+ - lib/activefacts/generator/traits/sql.rb
233
+ - lib/activefacts/generator/traits/sql/mysql.rb
234
+ - lib/activefacts/generator/traits/sql/oracle.rb
235
+ - lib/activefacts/generator/traits/sql/postgres.rb
236
+ - lib/activefacts/generator/traits/sql/server.rb
232
237
  - lib/activefacts/generator/transgen.rb
233
238
  - lib/activefacts/generator/validate.rb
234
239
  - lib/activefacts/loadable.rb