activefacts-compositions 1.9.14 → 1.9.15
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.
- 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
|