activefacts-compositions 1.9.14 → 1.9.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/activefacts-compositions.gemspec +1 -1
- data/bin/schema_compositor +4 -1
- data/lib/activefacts/compositions/relational.rb +33 -7
- data/lib/activefacts/compositions/version.rb +1 -1
- data/lib/activefacts/generator/rails/schema.rb +5 -0
- data/lib/activefacts/generator/sql.rb +147 -51
- data/lib/activefacts/generator/sql/postgres.rb +164 -0
- data/lib/activefacts/generator/sql/server.rb +26 -25
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1bf118df915877ab33968a6777b33a62cf37324
|
4
|
+
data.tar.gz: bd5400584518e29d8bdefc7caf593379805a6e35
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2012ef677cea2524ef6ff02df61e07af2822faad359ae4975f375ab374760db27d0ba981064969a55fabfcc13d2d24ec690b620f7c93281fded26764cf2f98f3
|
7
|
+
data.tar.gz: 30771fd537a8249d6f12f4c197eb1925e73cc2dc41222c6cc381591895216902bd7b479da6176309eae85eb8021ab7dd506701cd8429dfbcc82c7a08b905173d
|
@@ -29,6 +29,6 @@ Gem::Specification.new do |spec|
|
|
29
29
|
|
30
30
|
spec.add_development_dependency "activefacts", "~> 1", ">= 1.8"
|
31
31
|
spec.add_runtime_dependency "activefacts-api", "~> 1", ">= 1.9.11"
|
32
|
-
spec.add_runtime_dependency "activefacts-metamodel", "~> 1", ">= 1.9.
|
32
|
+
spec.add_runtime_dependency "activefacts-metamodel", "~> 1", ">= 1.9.19"
|
33
33
|
spec.add_runtime_dependency "activefacts-cql", "~> 1", ">= 1.9"
|
34
34
|
end
|
data/bin/schema_compositor
CHANGED
@@ -154,11 +154,14 @@ class SchemaCompositor
|
|
154
154
|
' num'
|
155
155
|
when Pathname
|
156
156
|
' file'
|
157
|
+
when Array
|
158
|
+
" { #{type.map(&:to_s)*' | '} }"
|
157
159
|
else
|
158
160
|
' str'
|
159
161
|
end
|
160
162
|
|
161
|
-
|
163
|
+
spaces = (s = 24-tag.size) < 2 ? 2 : s
|
164
|
+
stream.puts "\t#{tag}#{' '*spaces}#{description}"
|
162
165
|
end
|
163
166
|
end
|
164
167
|
end
|
@@ -37,6 +37,9 @@ module ActiveFacts
|
|
37
37
|
# Figure out how best to absorb things to reduce the number of tables
|
38
38
|
optimise_absorption
|
39
39
|
|
40
|
+
# If we have partitioned subtypes, make that happen
|
41
|
+
enact_partitioning
|
42
|
+
|
40
43
|
# Actually make a Composite object for each table:
|
41
44
|
make_composites
|
42
45
|
|
@@ -228,6 +231,17 @@ module ActiveFacts
|
|
228
231
|
end
|
229
232
|
end
|
230
233
|
|
234
|
+
def enact_partitioning
|
235
|
+
@constellation.EntityType.each do |key, object_type|
|
236
|
+
sti = object_type.all_type_inheritance_as_supertype
|
237
|
+
if sti.size > 0 && sti.size == sti.select{|ti| ti.assimilation == 'partitioned'}.size
|
238
|
+
trace :relational_optimiser, "Supertype #{object_type.name} is fully partitioned so not a table"
|
239
|
+
candidate = @candidates[object_type]
|
240
|
+
candidate.definitely_not_table
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
231
245
|
# Remove the unused reverse absorptions:
|
232
246
|
def delete_reverse_absorptions
|
233
247
|
@binary_mappings.each do |object_type, mapping|
|
@@ -561,11 +575,13 @@ module ActiveFacts
|
|
561
575
|
# This member is an Absorption. Process it recursively, absorbing all its members or just a key
|
562
576
|
# depending on whether the absorbed object is a Composite (or absorbed into one) or not.
|
563
577
|
def absorb_nested mapping, member, paths
|
564
|
-
#
|
578
|
+
# Is this where we absorb a partitioned supertype?
|
579
|
+
is_partitioned = (ft = member.child_role.fact_type).is_a?(MM::TypeInheritance) && ft.assimilation == 'partitioned'
|
565
580
|
|
581
|
+
# Should we absorb a foreign key or the whole contents?
|
566
582
|
child_object_type = member.child_role.object_type
|
567
583
|
child_mapping = @binary_mappings[child_object_type]
|
568
|
-
if child_mapping.composite
|
584
|
+
if child_mapping.composite && !is_partitioned
|
569
585
|
trace :relational_columns?, "Absorbing FK to #{member.child_role.name} in #{member.inspect_reading}" do
|
570
586
|
paths[member] = @constellation.ForeignKey(:new, source_composite: mapping.root, composite: child_mapping.composite, absorption: member)
|
571
587
|
absorb_key member, child_mapping, paths
|
@@ -594,6 +610,7 @@ module ActiveFacts
|
|
594
610
|
return
|
595
611
|
end
|
596
612
|
|
613
|
+
# REVISIT: if is_partitioned, don't absorb sibling subtypes!
|
597
614
|
trace :relational_columns?, "Absorbing all of #{member.child_role.name} in #{member.inspect_reading}" do
|
598
615
|
absorb_all member, child_mapping, paths
|
599
616
|
end
|
@@ -651,7 +668,7 @@ module ActiveFacts
|
|
651
668
|
|
652
669
|
pcs = []
|
653
670
|
newpaths = {}
|
654
|
-
if mapping.composite || mapping.full_absorption
|
671
|
+
if mapping.composite || mapping.full_absorption || mapping.parent_role.fact_type.is_a?(MM::TypeInheritance)
|
655
672
|
pcs = find_uniqueness_constraints(mapping)
|
656
673
|
|
657
674
|
# Don't build an index from the same PresenceConstraint twice on the same composite (e.g. for a subtype)
|
@@ -676,9 +693,18 @@ module ActiveFacts
|
|
676
693
|
end
|
677
694
|
end
|
678
695
|
|
696
|
+
# Delete indexes that accrued no fields:
|
679
697
|
newpaths.values.select{|ix| ix.all_index_field.size == 0}.each(&:retract)
|
680
698
|
end
|
681
699
|
|
700
|
+
# We include the subtype role of a TypeInheritance if
|
701
|
+
# it provides_identification or the subtype is not partitioned
|
702
|
+
def included_subtype role
|
703
|
+
role == role.fact_type.subtype_role &&
|
704
|
+
!role.object_type.is_partitioned &&
|
705
|
+
role.fact_type.provides_identification
|
706
|
+
end
|
707
|
+
|
682
708
|
# Find all PresenceConstraints to index the object in this Mapping
|
683
709
|
def find_uniqueness_constraints mapping
|
684
710
|
return [] unless mapping.object_type.is_a?(MM::EntityType)
|
@@ -686,11 +712,11 @@ module ActiveFacts
|
|
686
712
|
start_roles =
|
687
713
|
mapping.
|
688
714
|
object_type.
|
689
|
-
|
715
|
+
all_role. # Includes objectification roles for objectified fact types
|
690
716
|
select do |role|
|
691
717
|
(role.is_unique || # Must be unique on near role
|
692
718
|
role.fact_type.is_unary) && # Or be a unary role
|
693
|
-
!
|
719
|
+
(!role.fact_type.is_a?(MM::TypeInheritance) || included_subtype(role))
|
694
720
|
end.
|
695
721
|
map(&:counterpart). # (Same role if it's a unary)
|
696
722
|
compact. # Ignore nil counterpart of a role in an n-ary
|
@@ -750,8 +776,8 @@ module ActiveFacts
|
|
750
776
|
trace :relational_paths?, "Adding #{new_pcs.size} new indices for presence constraints on #{mapping.inspect}" do
|
751
777
|
new_pcs.each do |pc|
|
752
778
|
newpaths[pc] = index = @constellation.Index(:new, composite: mapping.root, is_unique: true, presence_constraint: pc)
|
753
|
-
if mapping.object_type.preferred_identifier == pc and
|
754
|
-
!@composition.all_full_absorption[mapping.object_type] and
|
779
|
+
if mapping.root.mapping.object_type.preferred_identifier == pc and
|
780
|
+
!@composition.all_full_absorption[mapping.object_type] and # REVISIT: This clause might now be unnecessary
|
755
781
|
!mapping.root.natural_index
|
756
782
|
mapping.root.natural_index = index
|
757
783
|
mapping.root.primary_index ||= index # Not if we have a surrogate already
|
@@ -88,6 +88,11 @@ module ActiveFacts
|
|
88
88
|
def generate_composite composite
|
89
89
|
ar_table_name = composite.rails.plural_name
|
90
90
|
|
91
|
+
pi = composite.primary_index
|
92
|
+
unless pi
|
93
|
+
warn "Warning: Cannot generate schema for #{composite.mapping.name} because it has no primary key"
|
94
|
+
return nil
|
95
|
+
end
|
91
96
|
pk = composite.primary_index.all_index_field.to_a
|
92
97
|
if pk[0].component.is_auto_assigned
|
93
98
|
identity_column = pk[0].component
|
@@ -20,20 +20,34 @@ module ActiveFacts
|
|
20
20
|
def self.options
|
21
21
|
{
|
22
22
|
delay_fks: ['Boolean', "Delay emitting all foreign keys until the bottom of the file"],
|
23
|
-
|
23
|
+
keywords: ['Boolean', "Quote all keywords, not just reserved words"],
|
24
|
+
restrict: ['String', "Restrict generation to tables in the specified group (e.g. bdv, rdv)"],
|
25
|
+
joiner: ['String', "Use 'str' instead of the default joiner between words in table and column names"],
|
24
26
|
unicode: ['Boolean', "Use Unicode for all text fields by default"],
|
25
|
-
|
26
|
-
|
27
|
+
tables: [%w{cap title camel snake shout}, "Case to use for table names"],
|
28
|
+
columns: [%w{cap title camel snake shout}, "Case to use for table names"],
|
29
|
+
# Legacy: datavault: ['String', "Generate 'raw' or 'business' data vault tables"],
|
27
30
|
}
|
28
31
|
end
|
29
32
|
|
30
33
|
def initialize composition, options = {}
|
31
34
|
@composition = composition
|
32
35
|
@options = options
|
36
|
+
@quote_keywords = {nil=>true, 't'=>true, 'f'=>false, 'y'=>true, 'n'=>false}[options.delete 'keywords']
|
37
|
+
@quote_keywords = false if @keywords == nil # Set default
|
33
38
|
@delay_fks = options.delete "delay_fks"
|
34
|
-
@underscore = options.has_key?("underscore") ? (options['underscore'] || '_') : ''
|
35
39
|
@unicode = options.delete "unicode"
|
36
40
|
@restrict = options.delete "restrict"
|
41
|
+
|
42
|
+
# Name configuration options:
|
43
|
+
@joiner = options.delete('joiner')
|
44
|
+
@table_joiner = options.has_key?('tables') ? @joiner : nil
|
45
|
+
@table_case = ((options.delete('tables') || 'cap') + 'words').to_sym
|
46
|
+
@table_joiner ||= [:snakewords, :shoutwords].include?(@table_case) ? '_' : ''
|
47
|
+
@column_joiner = options.has_key?('columns') ? @joiner : nil
|
48
|
+
@column_case = ((options.delete('columns') || 'cap') + 'words').to_sym
|
49
|
+
@column_joiner ||= [:snakewords, :shoutwords].include?(@column_case) ? '_' : ''
|
50
|
+
|
37
51
|
# Legacy option. Use restrict=bdv/rdv instead
|
38
52
|
@datavault = options.delete "datavault"
|
39
53
|
case @datavault
|
@@ -129,7 +143,7 @@ module ActiveFacts
|
|
129
143
|
"\t#{column_name}#{padding}#{column_type leaf, column_name}"
|
130
144
|
end
|
131
145
|
|
132
|
-
def
|
146
|
+
def auto_assign_modifier
|
133
147
|
' GENERATED ALWAYS AS IDENTITY'
|
134
148
|
end
|
135
149
|
|
@@ -138,7 +152,7 @@ module ActiveFacts
|
|
138
152
|
options ||= {}
|
139
153
|
length = options[:length]
|
140
154
|
value_constraint = options[:value_constraint]
|
141
|
-
type_name, length = normalise_type(type_name, length, value_constraint)
|
155
|
+
type_name, length = normalise_type(type_name, length, value_constraint, options)
|
142
156
|
|
143
157
|
"#{
|
144
158
|
type_name
|
@@ -147,7 +161,9 @@ module ActiveFacts
|
|
147
161
|
}#{
|
148
162
|
((options[:mandatory] ? ' NOT' : '') + ' NULL') if options.has_key?(:mandatory)
|
149
163
|
}#{
|
150
|
-
|
164
|
+
options[:default] || ''
|
165
|
+
}#{
|
166
|
+
auto_assign_modifier if a = options[:auto_assign] && a != 'assert'
|
151
167
|
}#{
|
152
168
|
check_clause(column_name, value_constraint) if value_constraint
|
153
169
|
}"
|
@@ -201,14 +217,20 @@ module ActiveFacts
|
|
201
217
|
end
|
202
218
|
|
203
219
|
# Return SQL type and (modified?) length for the passed base type
|
204
|
-
def normalise_type(type_name, length, value_constraint)
|
220
|
+
def normalise_type(type_name, length, value_constraint, options)
|
205
221
|
type = MM::DataType.normalise(type_name)
|
206
222
|
|
207
223
|
case type
|
208
224
|
when MM::DataType::TYPE_Boolean; data_type_context.boolean_type
|
209
225
|
when MM::DataType::TYPE_Integer
|
210
|
-
|
211
|
-
|
226
|
+
# The :auto_assign key is set for auto-assigned types, but with a nil value in foreign keys
|
227
|
+
if options.has_key?(:auto_assign)
|
228
|
+
MM::DataType.normalise_int_length(
|
229
|
+
'int',
|
230
|
+
data_type_context.default_surrogate_length,
|
231
|
+
value_constraint,
|
232
|
+
data_type_context
|
233
|
+
)[0]
|
212
234
|
else
|
213
235
|
v, = MM::DataType.normalise_int_length(type_name, length, value_constraint, data_type_context)
|
214
236
|
v # The typename here has the appropriate length, don't return a length
|
@@ -238,50 +260,123 @@ module ActiveFacts
|
|
238
260
|
|
239
261
|
def reserved_words
|
240
262
|
@reserved_words ||= %w{
|
241
|
-
ABSOLUTE ACTION ADD
|
242
|
-
ARRAY AS ASC
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
263
|
+
ABS ABSOLUTE ACTION ADD ALL ALLOCATE ALTER AND ANY ARE
|
264
|
+
ARRAY ARRAY_AGG ARRAY_MAX_CARDINALITY AS ASC ASENSITIVE
|
265
|
+
ASSERTION ASYMMETRIC AT ATOMIC AUTHORIZATION AVG BEGIN
|
266
|
+
BEGIN_FRAME BEGIN_PARTITION BETWEEN BIGINT BINARY BIT
|
267
|
+
BIT_LENGTH BLOB BOOLEAN BOTH BY CALL CALLED CARDINALITY
|
268
|
+
CASCADE CASCADED CASE CAST CATALOG CEIL CEILING CHAR
|
269
|
+
CHARACTER CHARACTER_LENGTH CHAR_LENGTH CHECK CLOB CLOSE
|
270
|
+
COALESCE COLLATE COLLATION COLLECT COLUMN COMMIT CONDITION
|
271
|
+
CONNECT CONNECTION CONSTRAINT CONSTRAINTS CONTAINS CONTINUE
|
272
|
+
CONVERT CORR CORRESPONDING COUNT COVAR_POP COVAR_SAMP
|
273
|
+
CREATE CROSS CUBE CUME_DIST CURRENT CURRENT_CATALOG
|
274
|
+
CURRENT_DATE CURRENT_DEFAULT_TRANSFORM_GROUP CURRENT_PATH
|
275
|
+
CURRENT_ROLE CURRENT_ROW CURRENT_SCHEMA CURRENT_TIME
|
276
|
+
CURRENT_TIMESTAMP CURRENT_TRANSFORM_GROUP_FOR_TYPE
|
277
|
+
CURRENT_USER CURSOR CYCLE DATALINK DATE DAY DEALLOCATE
|
278
|
+
DEC DECIMAL DECLARE DEFAULT DEFERRABLE DEFERRED DELETE
|
279
|
+
DENSE_RANK DEREF DESC DESCRIBE DESCRIPTOR DETERMINISTIC
|
280
|
+
DIAGNOSTICS DISCONNECT DISTINCT DLNEWCOPY DLPREVIOUSCOPY
|
281
|
+
DLURLCOMPLETE DLURLCOMPLETEONLY DLURLCOMPLETEWRITE DLURLPATH
|
282
|
+
DLURLPATHONLY DLURLPATHWRITE DLURLSCHEME DLURLSERVER
|
283
|
+
DLVALUE DO DOMAIN DOUBLE DROP DYNAMIC EACH ELEMENT ELSE
|
284
|
+
ELSEIF END END-EXEC END_FRAME END_PARTITION EQUALS ESCAPE
|
285
|
+
EVERY EXCEPT EXCEPTION EXEC EXECUTE EXISTS EXIT EXP
|
286
|
+
EXTERNAL EXTRACT FALSE FETCH FILTER FIRST FIRST_VALUE
|
287
|
+
FLOAT FLOOR FOR FOREIGN FOUND FRAME_ROW FREE FROM FULL
|
288
|
+
FUNCTION FUSION GET GLOBAL GO GOTO GRANT GROUP GROUPING
|
289
|
+
GROUPS HANDLER HAVING HOLD HOUR IDENTITY IF IMMEDIATE
|
290
|
+
IMPORT IN INDICATOR INITIALLY INNER INOUT INPUT INSENSITIVE
|
291
|
+
INSERT INT INTEGER INTERSECT INTERSECTION INTERVAL INTO
|
292
|
+
IS ISOLATION ITERATE JOIN KEY LAG LANGUAGE LARGE LAST
|
293
|
+
LAST_VALUE LATERAL LEAD LEADING LEAVE LEFT LEVEL LIKE
|
294
|
+
LIKE_REGEX LN LOCAL LOCALTIME LOCALTIMESTAMP LOOP LOWER
|
295
|
+
MATCH MAX MAX_CARDINALITY MEMBER MERGE METHOD MIN MINUTE
|
296
|
+
MOD MODIFIES MODULE MONTH MULTISET NAMES NATIONAL NATURAL
|
297
|
+
NCHAR NCLOB NEW NEXT NO NONE NORMALIZE NOT NTH_VALUE NTILE
|
298
|
+
NULL NULLIF NUMERIC OCCURRENCES_REGEX OCTET_LENGTH OF
|
299
|
+
OFFSET OLD ON ONLY OPEN OPTION OR ORDER OUT OUTER OUTPUT
|
300
|
+
OVER OVERLAPS OVERLAY PAD PARAMETER PARTIAL PARTITION
|
301
|
+
PERCENT PERCENTILE_CONT PERCENTILE_DISC PERCENT_RANK
|
302
|
+
PERIOD PORTION POSITION POSITION_REGEX POWER PRECEDES
|
303
|
+
PRECISION PREPARE PRESERVE PRIMARY PRIOR PRIVILEGES
|
304
|
+
PROCEDURE PUBLIC RANGE RANK READ READS REAL RECURSIVE REF
|
305
|
+
REFERENCES REFERENCING REGR_AVGX REGR_AVGY REGR_COUNT
|
306
|
+
REGR_INTERCEPT REGR_R2 REGR_SLOPE REGR_SXX REGR_SXY
|
307
|
+
REGR_SYY RELATIVE RELEASE REPEAT RESIGNAL RESTRICT RESULT
|
308
|
+
RETURN RETURNS REVOKE RIGHT ROLLBACK ROLLUP ROW ROWS
|
309
|
+
ROW_NUMBER SAVEPOINT SCHEMA SCOPE SCROLL SEARCH SECOND
|
310
|
+
SECTION SELECT SENSITIVE SESSION SESSION_USER SET SIGNAL
|
311
|
+
SIMILAR SIZE SMALLINT SOME SPACE SPECIFIC SPECIFICTYPE
|
312
|
+
SQL SQLCODE SQLERROR SQLEXCEPTION SQLSTATE SQLWARNING
|
313
|
+
SQRT START STATIC STDDEV_POP STDDEV_SAMP SUBMULTISET
|
314
|
+
SUBSTRING SUBSTRING_REGEX SUCCEEDS SUM SYMMETRIC SYSTEM
|
315
|
+
SYSTEM_TIME SYSTEM_USER TABLE TABLESAMPLE TEMPORARY THEN
|
316
|
+
TIME TIMESTAMP TIMEZONE_HOUR TIMEZONE_MINUTE TO TRAILING
|
317
|
+
TRANSACTION TRANSLATE TRANSLATE_REGEX TRANSLATION TREAT
|
318
|
+
TRIGGER TRIM TRIM_ARRAY TRUE TRUNCATE UESCAPE UNDO UNION
|
319
|
+
UNIQUE UNKNOWN UNNEST UNTIL UPDATE UPPER USAGE USER USING
|
320
|
+
VALUE VALUES VALUE_OF VARBINARY VARCHAR VARYING VAR_POP
|
321
|
+
VAR_SAMP VERSIONING VIEW WHEN WHENEVER WHERE WHILE
|
322
|
+
WIDTH_BUCKET WINDOW WITH WITHIN WITHOUT WORK WRITE XML
|
323
|
+
XMLAGG XMLATTRIBUTES XMLBINARY XMLCAST XMLCOMMENT XMLCONCAT
|
324
|
+
XMLDOCUMENT XMLELEMENT XMLEXISTS XMLFOREST XMLITERATE
|
325
|
+
XMLNAMESPACES XMLPARSE XMLPI XMLQUERY XMLSERIALIZE XMLTABLE
|
326
|
+
XMLTEXT XMLVALIDATE YEAR ZONE
|
327
|
+
}
|
328
|
+
end
|
329
|
+
|
330
|
+
def key_words
|
331
|
+
@key_words ||= %w{
|
332
|
+
A ABSENT ACCORDING ADA ADMIN AFTER ALWAYS ASSIGNMENT
|
333
|
+
ATTRIBUTE ATTRIBUTES BASE64 BEFORE BERNOULLI BLOCKED BOM
|
334
|
+
BREADTH C CATALOG_NAME CHAIN CHARACTERISTICS CHARACTERS
|
335
|
+
CHARACTER_SET_CATALOG CHARACTER_SET_NAME CHARACTER_SET_SCHEMA
|
336
|
+
CLASS_ORIGIN COBOL COLLATION_CATALOG COLLATION_NAME
|
337
|
+
COLLATION_SCHEMA COLUMNS COLUMN_NAME COMMAND_FUNCTION
|
338
|
+
COMMAND_FUNCTION_CODE COMMITTED CONDITION_NUMBER
|
339
|
+
CONNECTION_NAME CONSTRAINT_CATALOG CONSTRAINT_NAME
|
340
|
+
CONSTRAINT_SCHEMA CONSTRUCTOR CONTENT CONTROL CURSOR_NAME
|
341
|
+
DATA DATETIME_INTERVAL_CODE DATETIME_INTERVAL_PRECISION
|
342
|
+
DB DEFAULTS DEFINED DEFINER DEGREE DEPTH DERIVED DISPATCH
|
343
|
+
DOCUMENT DYNAMIC_FUNCTION DYNAMIC_FUNCTION_CODE EMPTY
|
344
|
+
ENCODING ENFORCED EXCLUDE EXCLUDING EXPRESSION FILE FINAL
|
345
|
+
FLAG FOLLOWING FORTRAN FS G GENERAL GENERATED GRANTED HEX
|
346
|
+
HIERARCHY ID IGNORE IMMEDIATELY IMPLEMENTATION INCLUDING
|
347
|
+
INCREMENT INDENT INSTANCE INSTANTIABLE INSTEAD INTEGRITY
|
348
|
+
INVOKER K KEY_MEMBER KEY_TYPE LENGTH LIBRARY LIMIT LINK
|
349
|
+
LOCATION LOCATOR M MAP MAPPING MATCHED MAXVALUE MESSAGE_LENGTH
|
350
|
+
MESSAGE_OCTET_LENGTH MESSAGE_TEXT MINVALUE MORE MUMPS
|
351
|
+
NAME NAMESPACE NESTING NFC NFD NFKC NFKD NIL NORMALIZED
|
352
|
+
NULLABLE NULLS NUMBER OBJECT OCTETS OFF OPTIONS ORDERING
|
353
|
+
ORDINALITY OTHERS OVERRIDING P PARAMETER_MODE PARAMETER_NAME
|
354
|
+
PARAMETER_ORDINAL_POSITION PARAMETER_SPECIFIC_CATALOG
|
355
|
+
PARAMETER_SPECIFIC_NAME PARAMETER_SPECIFIC_SCHEMA PASCAL
|
356
|
+
PASSING PASSTHROUGH PATH PERMISSION PLACING PLI PRECEDING
|
357
|
+
RECOVERY REPEATABLE REQUIRING RESPECT RESTART RESTORE
|
358
|
+
RETURNED_CARDINALITY RETURNED_LENGTH RETURNED_OCTET_LENGTH
|
359
|
+
RETURNED_SQLSTATE RETURNING ROLE ROUTINE ROUTINE_CATALOG
|
360
|
+
ROUTINE_NAME ROUTINE_SCHEMA ROW_COUNT SCALE SCHEMA_NAME
|
361
|
+
SCOPE_CATALOG SCOPE_NAME SCOPE_SCHEMA SECURITY SELECTIVE
|
362
|
+
SELF SEQUENCE SERIALIZABLE SERVER SERVER_NAME SETS SIMPLE
|
363
|
+
SOURCE SPECIFIC_NAME STANDALONE STATE STATEMENT STRIP
|
364
|
+
STRUCTURE STYLE SUBCLASS_ORIGIN T TABLE_NAME TIES TOKEN
|
365
|
+
TOP_LEVEL_COUNT TRANSACTIONS_COMMITTED TRANSACTIONS_ROLLED_BACK
|
366
|
+
TRANSACTION_ACTIVE TRANSFORM TRANSFORMS TRIGGER_CATALOG
|
367
|
+
TRIGGER_NAME TRIGGER_SCHEMA TYPE UNBOUNDED UNCOMMITTED
|
368
|
+
UNDER UNLINK UNNAMED UNTYPED URI USER_DEFINED_TYPE_CATALOG
|
369
|
+
USER_DEFINED_TYPE_CODE USER_DEFINED_TYPE_NAME
|
370
|
+
USER_DEFINED_TYPE_SCHEMA VALID VERSION WHITESPACE WRAPPER
|
371
|
+
XMLDECLARATION XMLSCHEMA YES
|
279
372
|
}
|
280
373
|
end
|
281
374
|
|
282
375
|
def is_reserved_word w
|
283
376
|
@reserved_word_hash ||=
|
284
|
-
|
377
|
+
( reserved_words +
|
378
|
+
(@quote_keywords ? key_words : [])).
|
379
|
+
inject({}) do |h,w|
|
285
380
|
h[w] = true
|
286
381
|
h
|
287
382
|
end
|
@@ -425,11 +520,12 @@ module ActiveFacts
|
|
425
520
|
end
|
426
521
|
|
427
522
|
def table_name composite
|
428
|
-
composite.mapping.name.
|
523
|
+
composite.mapping.name.words.send(@table_case)*@table_joiner
|
429
524
|
end
|
430
525
|
|
431
526
|
def column_name component
|
432
|
-
component.column_name.
|
527
|
+
words = component.column_name.send(@column_case)
|
528
|
+
words*@column_joiner
|
433
529
|
end
|
434
530
|
|
435
531
|
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Standard SQL Schema Generator
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009-2016 Clifford Heath. Read the LICENSE file.
|
5
|
+
#
|
6
|
+
require 'digest/sha1'
|
7
|
+
require 'activefacts/metamodel'
|
8
|
+
require 'activefacts/compositions'
|
9
|
+
require 'activefacts/generator/sql'
|
10
|
+
|
11
|
+
module ActiveFacts
|
12
|
+
module Generators
|
13
|
+
# Options are comma or space separated:
|
14
|
+
# * underscore
|
15
|
+
class SQL
|
16
|
+
class Postgres < SQL
|
17
|
+
def self.options
|
18
|
+
super.merge({
|
19
|
+
# no: [String, "no new options defined here"]
|
20
|
+
})
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize composition, options = {}
|
24
|
+
super(composition, {'tables' => 'snake', 'columns' => 'snake'}.merge(options))
|
25
|
+
end
|
26
|
+
|
27
|
+
def table_name_max
|
28
|
+
63
|
29
|
+
end
|
30
|
+
|
31
|
+
def data_type_context
|
32
|
+
PostgresqlDataTypeContext.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def auto_assign_modifier
|
36
|
+
''
|
37
|
+
end
|
38
|
+
|
39
|
+
def generate_schema
|
40
|
+
go "CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public"
|
41
|
+
end
|
42
|
+
|
43
|
+
def normalise_type(type_name, length, value_constraint, options)
|
44
|
+
if type_name =~ /^(guid|uuid)$/i
|
45
|
+
if ![nil, ''].include?(options[:auto_assign])
|
46
|
+
options[:default] = " DEFAULT 'gen_random_uuid()'"
|
47
|
+
end
|
48
|
+
return ['UUID']
|
49
|
+
end
|
50
|
+
|
51
|
+
type = MM::DataType.normalise(type_name)
|
52
|
+
case type
|
53
|
+
when MM::DataType::TYPE_Integer
|
54
|
+
if aa = options[:auto_assign]
|
55
|
+
if aa.size > 0
|
56
|
+
'BIGSERIAL'
|
57
|
+
else
|
58
|
+
'BIGINT'
|
59
|
+
end
|
60
|
+
else
|
61
|
+
super
|
62
|
+
end
|
63
|
+
when MM::DataType::TYPE_Money; 'MONEY'
|
64
|
+
when MM::DataType::TYPE_DateTime; 'DATETIME'
|
65
|
+
when MM::DataType::TYPE_Timestamp;'DATETIME'
|
66
|
+
when MM::DataType::TYPE_Binary;
|
67
|
+
if length && length <= 8192
|
68
|
+
super
|
69
|
+
else
|
70
|
+
'IMAGE'
|
71
|
+
end
|
72
|
+
else
|
73
|
+
super
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Reserved words cannot be used anywhere without quoting.
|
78
|
+
# Keywords have existing definitions, so should not be used without quoting.
|
79
|
+
# Both lists here are added to the supertype's lists
|
80
|
+
def reserved_words
|
81
|
+
@postgres_reserved_words ||= %w{
|
82
|
+
ANALYSE ANALYZE LIMIT PLACING RETURNING VARIADIC
|
83
|
+
}
|
84
|
+
super + @postgres_reserved_words
|
85
|
+
end
|
86
|
+
|
87
|
+
def key_words
|
88
|
+
# These keywords should not be used for columns or tables:
|
89
|
+
@postgres_key_words ||= %w{
|
90
|
+
ABORT ACCESS AGGREGATE ALSO BACKWARD CACHE CHECKPOINT
|
91
|
+
CLASS CLUSTER COMMENT COMMENTS CONFIGURATION CONFLICT
|
92
|
+
CONVERSION COPY COST CSV DATABASE DELIMITER DELIMITERS
|
93
|
+
DICTIONARY DISABLE DISCARD ENABLE ENCRYPTED ENUM EVENT
|
94
|
+
EXCLUSIVE EXPLAIN EXTENSION FAMILY FORCE FORWARD FUNCTIONS
|
95
|
+
HEADER IMMUTABLE IMPLICIT INDEX INDEXES INHERIT INHERITS
|
96
|
+
INLINE LABEL LEAKPROOF LISTEN LOAD LOCK LOCKED LOGGED
|
97
|
+
MATERIALIZED MODE MOVE NOTHING NOTIFY NOWAIT OIDS
|
98
|
+
OPERATOR OWNED OWNER PARSER PASSWORD PLANS POLICY
|
99
|
+
PREPARED PROCEDURAL PROGRAM QUOTE REASSIGN RECHECK
|
100
|
+
REFRESH REINDEX RENAME REPLACE REPLICA RESET RULE
|
101
|
+
SEQUENCES SHARE SHOW SKIP SNAPSHOT STABLE STATISTICS
|
102
|
+
STDIN STDOUT STORAGE STRICT SYSID TABLES TABLESPACE
|
103
|
+
TEMP TEMPLATE TEXT TRUSTED TYPES UNENCRYPTED UNLISTEN
|
104
|
+
UNLOGGED VACUUM VALIDATE VALIDATOR VIEWS VOLATILE
|
105
|
+
}
|
106
|
+
|
107
|
+
# These keywords cannot be used for type or functions (and should not for columns or tables)
|
108
|
+
@postgres_key_words_func_type ||= %w{
|
109
|
+
GREATEST LEAST SETOF XMLROOT
|
110
|
+
}
|
111
|
+
super + @postgres_key_words + @postgres_key_words_func_type
|
112
|
+
end
|
113
|
+
|
114
|
+
def go s = ''
|
115
|
+
"#{s};\n\n"
|
116
|
+
end
|
117
|
+
|
118
|
+
def open_escape
|
119
|
+
'"'
|
120
|
+
end
|
121
|
+
|
122
|
+
def close_escape
|
123
|
+
'"'
|
124
|
+
end
|
125
|
+
|
126
|
+
def index_kind(index)
|
127
|
+
''
|
128
|
+
end
|
129
|
+
|
130
|
+
class PostgresqlDataTypeContext < SQLDataTypeContext
|
131
|
+
def integer_ranges
|
132
|
+
super
|
133
|
+
end
|
134
|
+
|
135
|
+
def boolean_type
|
136
|
+
'BOOLEAN'
|
137
|
+
end
|
138
|
+
|
139
|
+
def valid_from_type
|
140
|
+
'TIMESTAMP'
|
141
|
+
end
|
142
|
+
|
143
|
+
# There is no performance benefit in using fixed-length CHAR fields,
|
144
|
+
# and an added burden of trimming the implicitly added white-space
|
145
|
+
def default_char_type
|
146
|
+
(@unicode ? 'N' : '') +
|
147
|
+
'VARCHAR'
|
148
|
+
end
|
149
|
+
|
150
|
+
def default_varchar_type
|
151
|
+
(@unicode ? 'N' : '') +
|
152
|
+
'VARCHAR'
|
153
|
+
end
|
154
|
+
|
155
|
+
def date_time_type
|
156
|
+
'TIMESTAMP'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
publish_generator SQL::Postgres
|
163
|
+
end
|
164
|
+
end
|
@@ -28,7 +28,7 @@ module ActiveFacts
|
|
28
28
|
SQLServerDataTypeContext.new
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
31
|
+
def auto_assign_modifier
|
32
32
|
' IDENTITY'
|
33
33
|
end
|
34
34
|
|
@@ -51,32 +51,33 @@ module ActiveFacts
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
# Reserved words cannot be used anywhere without quoting.
|
55
|
+
# Keywords have existing definitions, so should not be used without quoting.
|
56
|
+
# Both lists here are added to the supertype's lists
|
54
57
|
def reserved_words
|
55
|
-
@
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
LINENO LOAD NATIONAL NOCHECK NONCLUSTERED NOT NULL NULLIF
|
69
|
-
OF OFF OFFSETS ON OPEN OPENDATASOURCE OPENQUERY OPENROWSET
|
70
|
-
OPENXML OPTION OR ORDER OUTER OVER PERCENT PLAN PRECISION
|
71
|
-
PRIMARY PRINT PROC PROCEDURE PUBLIC RAISERROR READ READTEXT
|
72
|
-
RECONFIGURE REFERENCES REPLICATION RESTORE RESTRICT RETURN
|
73
|
-
REVOKE RIGHT ROLLBACK ROWCOUNT ROWGUIDCOL RULE SAVE SCHEMA
|
74
|
-
SELECT SESSION_USER SET SETUSER SHUTDOWN SOME STATISTICS
|
75
|
-
SYSTEM_USER TABLE TEXTSIZE THEN TO TOP TRAN TRANSACTION
|
76
|
-
TRIGGER TRUNCATE TSEQUAL UNION UNIQUE UPDATE UPDATETEXT
|
77
|
-
USE USER VALUES VARYING VIEW WAITFOR WHEN WHERE WHILE
|
78
|
-
WITH WRITETEXT
|
58
|
+
@sqlserver_reserved_words ||= %w{
|
59
|
+
BACKUP BREAK BROWSE BULK CHECKPOINT CLUSTERED COMPUTE
|
60
|
+
CONTAINSTABLE DATABASE DBCC DENY DISK DISTRIBUTED DUMP
|
61
|
+
ERRLVL FILE FILLFACTOR FREETEXT FREETEXTTABLE HOLDLOCK
|
62
|
+
IDENTITYCOL IDENTITY_INSERT INDEX KILL LINENO LOAD
|
63
|
+
NOCHECK NONCLUSTERED OFF OFFSETS OPENDATASOURCE OPENQUERY
|
64
|
+
OPENROWSET OPENXML PIVOT PLAN PRINT PROC RAISERROR
|
65
|
+
READTEXT RECONFIGURE REPLICATION RESTORE REVERT ROWCOUNT
|
66
|
+
ROWGUIDCOL RULE SAVE SECURITYAUDIT SEMANTICKEYPHRASETABLE
|
67
|
+
SEMANTICSIMILARITYDETAILSTABLE SEMANTICSIMILARITYTABLE
|
68
|
+
SETUSER SHUTDOWN STATISTICS TEXTSIZE TOP TRAN TRY_CONVERT
|
69
|
+
TSEQUAL UNPIVOT UPDATETEXT USE WAITFOR WITHIN GROUP
|
70
|
+
WRITETEXT
|
79
71
|
}
|
72
|
+
super + @sqlserver_reserved_words
|
73
|
+
end
|
74
|
+
|
75
|
+
def key_words
|
76
|
+
# These keywords should not be used for columns or tables:
|
77
|
+
@sqlserver_key_words ||= %w{
|
78
|
+
INCLUDE INDEX SQLCA
|
79
|
+
}
|
80
|
+
super + @sqlserver_key_words
|
80
81
|
end
|
81
82
|
|
82
83
|
def go s = ''
|
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.
|
4
|
+
version: 1.9.15
|
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
|
+
date: 2017-11-09 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.
|
152
|
+
version: 1.9.19
|
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.
|
162
|
+
version: 1.9.19
|
163
163
|
- !ruby/object:Gem::Dependency
|
164
164
|
name: activefacts-cql
|
165
165
|
requirement: !ruby/object:Gem::Requirement
|
@@ -222,6 +222,7 @@ files:
|
|
222
222
|
- lib/activefacts/generator/rails/schema.rb
|
223
223
|
- lib/activefacts/generator/ruby.rb
|
224
224
|
- lib/activefacts/generator/sql.rb
|
225
|
+
- lib/activefacts/generator/sql/postgres.rb
|
225
226
|
- lib/activefacts/generator/sql/server.rb
|
226
227
|
- lib/activefacts/generator/summary.rb
|
227
228
|
- lib/activefacts/generator/transgen.rb
|