activefacts-metamodel 1.9.20 → 1.9.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/cql/Metamodel.cql +25 -23
- data/images/Absorption.png +0 -0
- data/images/Components.png +0 -0
- data/images/Compositions.png +0 -0
- data/images/Concepts.png +0 -0
- data/images/Nesting.png +0 -0
- data/images/Queries.png +0 -0
- data/images/Transformations.png +0 -0
- data/images/ValueTypes.png +0 -0
- data/lib/activefacts/metamodel/datatypes.rb +32 -22
- data/lib/activefacts/metamodel/extensions.rb +181 -130
- data/lib/activefacts/metamodel/metamodel.rb +115 -93
- data/lib/activefacts/metamodel/validate/composition.rb +9 -10
- data/lib/activefacts/metamodel/version.rb +1 -1
- data/lib/activefacts/support.rb +6 -1
- data/orm/Metamodel.cql.diffs +22 -22
- data/orm/Metamodel.orm +4954 -4577
- metadata +3 -3
- data/images/Transforms.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f78f93ff86302b754f0170041f1e5118a08dbbe
|
4
|
+
data.tar.gz: d6ade4f75f9960d866088c9c0fc8d6def107bd4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 423622558e664532cff04bc8fa9f8ef418e7f0d437894336d6715063744980110c87df94b4308a8aac0908f6c69995d249f970f14c460aaa75722348a18def1a
|
7
|
+
data.tar.gz: 837e537f5da6ca45fb8b5590222844e75124a1a80533173773ac3ea7ae05027de4e7b4c193a4a36be4d4f0e08907d445a0a4053f5efae20b88c491b0a25a1933
|
data/.gitignore
CHANGED
data/cql/Metamodel.cql
CHANGED
@@ -28,6 +28,7 @@ Offset is written as Decimal;
|
|
28
28
|
Ordinal is written as Unsigned Integer(16);
|
29
29
|
Pronoun is written as String(20) restricted to {'feminine', 'masculine', 'neuter', 'personal'};
|
30
30
|
Regular Expression is written as String;
|
31
|
+
Restriction Style is written as String restricted to {'ascending', 'descending', 'fixed'};
|
31
32
|
Ring Type is written as String;
|
32
33
|
Rotation Setting is written as String restricted to {'left', 'right'};
|
33
34
|
Scale is written as Unsigned Integer(32);
|
@@ -362,12 +363,12 @@ Value Type is subtype of at most one super-Value Type (as Supertype) [acyclic, t
|
|
362
363
|
Value Type Parameter is where
|
363
364
|
Value Type has parameter called Name,
|
364
365
|
Name identifies parameter of Value Type;
|
366
|
+
Value Type Parameter has at most one Restriction Style;
|
365
367
|
Value Type Parameter requires value of one parameter-Value Type;
|
366
368
|
|
367
369
|
Value Type Parameter Restriction is where
|
368
|
-
Value Type
|
369
|
-
|
370
|
-
Value Type Parameter Restriction has one Value;
|
370
|
+
Value Type allows Value Type Parameter to have Value Range;
|
371
|
+
|
371
372
|
|
372
373
|
/*
|
373
374
|
* Compositions
|
@@ -387,6 +388,7 @@ Component (as Member) belongs to at most one Component (as Parent) [acyclic, str
|
|
387
388
|
Component projects at most one Name;
|
388
389
|
Component has at most one Ordinal rank;
|
389
390
|
Component has absolute name;
|
391
|
+
Component has at most one injection-Annotation;
|
390
392
|
|
391
393
|
Indicator is a kind of Component;
|
392
394
|
Indicator indicates one Role played;
|
@@ -398,9 +400,20 @@ Discriminated Role is where
|
|
398
400
|
Discriminator distinguishes Role using one Value,
|
399
401
|
Role is indicated by Value for Discriminator;
|
400
402
|
|
403
|
+
Injection is a kind of Component;
|
404
|
+
Surrogate Key is a kind of Injection;
|
405
|
+
Computed Value is a kind of Injection;
|
406
|
+
Hash Value is a kind of Computed Value;
|
407
|
+
Component Hash is where
|
408
|
+
Hash Value covers at least one Component;
|
409
|
+
either Injection is a Surrogate Key
|
410
|
+
or Injection is a Computed Value but not both;
|
411
|
+
|
401
412
|
Mapping is a kind of Component;
|
402
413
|
Mapping represents one Object Type;
|
403
414
|
Mapping uses at most one native- type Name;
|
415
|
+
forward-Mapping is matched by at most one reverse-Mapping,
|
416
|
+
reverse-Mapping is reverse of at most one forward-Mapping;
|
404
417
|
|
405
418
|
Composite is identified by Mapping where
|
406
419
|
Mapping projects at most one Composite,
|
@@ -411,14 +424,9 @@ Composition contains Composite,
|
|
411
424
|
each Composite Group is identified by Name;
|
412
425
|
Composite belongs to at most one Composite Group;
|
413
426
|
|
414
|
-
Temporal Mapping is a kind of Mapping;
|
415
|
-
Temporal Mapping records time using one Value Type;
|
416
|
-
|
417
427
|
Absorption is a kind of Mapping;
|
418
428
|
Absorption traverses to one child-Role;
|
419
429
|
Absorption traverses from one parent-Role;
|
420
|
-
forward-Absorption is matched by at most one reverse-Absorption,
|
421
|
-
reverse-Absorption is reverse of at most one forward-Absorption;
|
422
430
|
Absorption flattens;
|
423
431
|
|
424
432
|
some Absorption traverses from some parent- Role(1) and that Role(1) is played by some Object Type
|
@@ -429,8 +437,8 @@ some Absorption traverses to some child- Role(1) and that Role(1) is played by s
|
|
429
437
|
|
430
438
|
Full Absorption is where
|
431
439
|
Composition fully absorbs Object Type;
|
432
|
-
Full Absorption applies to one
|
433
|
-
|
440
|
+
Full Absorption applies to one Mapping,
|
441
|
+
Mapping creates at most one Full Absorption;
|
434
442
|
/*
|
435
443
|
some Object Type is involved in some Full Absorption that applies to some Absorption that is a kind of Mapping
|
436
444
|
if and only if
|
@@ -453,10 +461,8 @@ Spanning Constraint is where
|
|
453
461
|
Constraint spans Composite;
|
454
462
|
|
455
463
|
Scoping is a kind of Mapping;
|
456
|
-
|
457
|
-
|
458
|
-
Surrogate Key is a kind of Injection;
|
459
|
-
Valid From is a kind of Injection;
|
464
|
+
Value Field is a kind of Mapping;
|
465
|
+
Valid From is a kind of Mapping;
|
460
466
|
|
461
467
|
/* Access Paths */
|
462
468
|
Access Path is identified by Guid where
|
@@ -469,7 +475,7 @@ Access Path is to one Composite,
|
|
469
475
|
/* Indices */
|
470
476
|
Index is a kind of Access Path;
|
471
477
|
Index is unique;
|
472
|
-
Index derives from one Presence Constraint;
|
478
|
+
Index derives from at most one Presence Constraint;
|
473
479
|
Composite has at most one natural-Index,
|
474
480
|
Index is natural for at most one Composite;
|
475
481
|
Composite has primary-Index; // Avoid ambiguity; this is a new fact type
|
@@ -493,8 +499,8 @@ Foreign Key is a kind of Access Path;
|
|
493
499
|
either Access Path is an Index or Access Path is a Foreign Key but not both;
|
494
500
|
Foreign Key traverses from one source-Composite,
|
495
501
|
Composite contains Foreign Key;
|
496
|
-
Foreign Key derives from one
|
497
|
-
|
502
|
+
Foreign Key derives from at most one Mapping,
|
503
|
+
Mapping gives rise to at most one Foreign Key;
|
498
504
|
|
499
505
|
Foreign Key Field is where
|
500
506
|
Foreign Key for Ordinal field uses one Component,
|
@@ -660,7 +666,8 @@ either Component(1) belongs to Component(2) or Component(1) is a Mapping that pr
|
|
660
666
|
for each Component exactly one of these holds:
|
661
667
|
Component is a Mapping,
|
662
668
|
Component is an Indicator,
|
663
|
-
Component is a Discriminator
|
669
|
+
Component is a Discriminator,
|
670
|
+
Component is an Injection;
|
664
671
|
for each Concept exactly one of these holds:
|
665
672
|
Object Type is an instance of Concept,
|
666
673
|
Fact Type is an instance of Concept,
|
@@ -678,11 +685,6 @@ for each Constraint exactly one of these holds:
|
|
678
685
|
Constraint is a Ring Constraint,
|
679
686
|
Constraint is a Value Constraint;
|
680
687
|
either Domain Object Type is a Value Type or Domain Object Type is an Entity Type but not both;
|
681
|
-
for each Mapping exactly one of these holds:
|
682
|
-
Mapping is an Absorption,
|
683
|
-
Mapping is an Injection,
|
684
|
-
Mapping is a Scoping,
|
685
|
-
Mapping projects Composite;
|
686
688
|
for each Role Sequence exactly one of these holds:
|
687
689
|
Role Sequence is for Reading,
|
688
690
|
Presence Constraint covers Role Sequence,
|
data/images/Absorption.png
CHANGED
Binary file
|
data/images/Components.png
CHANGED
Binary file
|
data/images/Compositions.png
CHANGED
Binary file
|
data/images/Concepts.png
CHANGED
Binary file
|
data/images/Nesting.png
CHANGED
Binary file
|
data/images/Queries.png
CHANGED
Binary file
|
Binary file
|
data/images/ValueTypes.png
CHANGED
Binary file
|
@@ -25,7 +25,7 @@ module ActiveFacts
|
|
25
25
|
TYPE_Boolean =>
|
26
26
|
%w{ bit },
|
27
27
|
TYPE_Integer =>
|
28
|
-
%w{ auto_counter int tiny_int small_int big_int unsigned unsigned_int unsigned_integer signed_int signed_integer},
|
28
|
+
%w{ auto_counter int tiny_int small_int big_int long_integer unsigned unsigned_int unsigned_integer signed_int signed_integer},
|
29
29
|
TYPE_Real =>
|
30
30
|
%w{ float double },
|
31
31
|
TYPE_Decimal =>
|
@@ -47,7 +47,7 @@ module ActiveFacts
|
|
47
47
|
TYPE_Timestamp =>
|
48
48
|
%w{ time_stamp auto_time_stamp },
|
49
49
|
TYPE_Binary =>
|
50
|
-
%w{ guid picture_raw_data variable_length_raw_data },
|
50
|
+
%w{ binary blob guid picture_raw_data variable_length_raw_data },
|
51
51
|
}
|
52
52
|
TypeParameters = {
|
53
53
|
TYPE_Integer => [:length], # Length is the number of bits
|
@@ -63,13 +63,17 @@ module ActiveFacts
|
|
63
63
|
# A DataType Context class should refine this class.
|
64
64
|
# The default context might work for you.
|
65
65
|
class Context
|
66
|
+
def initialize options = {}
|
67
|
+
raise "Unused options in DataType::Context: #{options.inspect}" unless options.empty?
|
68
|
+
end
|
69
|
+
|
66
70
|
def integer_ranges
|
67
71
|
end
|
68
72
|
|
69
73
|
def default_length data_type, type_name
|
70
74
|
end
|
71
75
|
|
72
|
-
def
|
76
|
+
def choose_integer_range min, max
|
73
77
|
integer_ranges.
|
74
78
|
select{|type_name, vmin, vmax| min >= vmin && max <= vmax}.
|
75
79
|
sort_by{|type_name, vmin, vmax| vmax-vmin}[0] # Choose the smallest range
|
@@ -103,7 +107,7 @@ module ActiveFacts
|
|
103
107
|
when /([a-z ]|\b)Small([a-z ]|\b)/i,
|
104
108
|
/([a-z ]|\b)Short([a-z ]|\b)/i
|
105
109
|
16
|
106
|
-
when /([a-z ]|\b)Big([a-z ]|\b)/i
|
110
|
+
when /([a-z ]|\b)(Big|Long)([a-z ]|\b)/i
|
107
111
|
64
|
108
112
|
else
|
109
113
|
32
|
@@ -122,12 +126,13 @@ module ActiveFacts
|
|
122
126
|
end
|
123
127
|
end
|
124
128
|
|
125
|
-
def self.
|
129
|
+
def self.intrinsic_type type_name
|
126
130
|
data_type, = type_mapping.detect{|t, names| names.detect{|n| n === type_name}}
|
127
131
|
data_type
|
128
132
|
end
|
129
133
|
|
130
|
-
|
134
|
+
# Integers are available in multiple sizes. Choose the most appropriate one.
|
135
|
+
def self.choose_integer type_name, length = nil, value_constraint = nil, context = DefaultContext.new
|
131
136
|
int_length = length || context.default_length(TYPE_Integer, type_name)
|
132
137
|
if int_length
|
133
138
|
if value_constraint
|
@@ -145,14 +150,18 @@ module ActiveFacts
|
|
145
150
|
int_max = unsigned ? 2**(int_length-1) - 1 : 2**(int_length-1)-1
|
146
151
|
max = int_max if !max || length && int_max < max
|
147
152
|
end
|
148
|
-
best = context.
|
153
|
+
best = context.choose_integer_range(min, max)
|
149
154
|
unless best || length
|
150
155
|
# Use the largest available integer size
|
151
156
|
best = context.integer_ranges.last
|
152
157
|
end
|
153
158
|
|
154
159
|
# Use a context-defined integer size if one suits, otherwise the requested size:
|
155
|
-
|
160
|
+
if best
|
161
|
+
best[0]
|
162
|
+
else
|
163
|
+
nil # No integer seems suitable
|
164
|
+
end
|
156
165
|
end
|
157
166
|
|
158
167
|
private
|
@@ -180,6 +189,11 @@ module ActiveFacts
|
|
180
189
|
primary_index.all_index_field.detect{|ixf| ixf.component == self}
|
181
190
|
end
|
182
191
|
|
192
|
+
def in_natural_index
|
193
|
+
natural_index = root.natural_index and
|
194
|
+
natural_index.all_index_field.detect{|ixf| ixf.component == self}
|
195
|
+
end
|
196
|
+
|
183
197
|
def in_foreign_key
|
184
198
|
all_foreign_key_field.detect{|fkf| fkf.foreign_key.source_composite == root}
|
185
199
|
end
|
@@ -190,17 +204,15 @@ module ActiveFacts
|
|
190
204
|
context.boolean_type
|
191
205
|
|
192
206
|
when SurrogateKey
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
]
|
199
|
-
|
200
|
-
when ValidFrom
|
201
|
-
object_type.name
|
207
|
+
type_name, options = *context.surrogate_type
|
208
|
+
options ||= {}
|
209
|
+
# Flag but disable auto-assignment for a surrogate that's an FK (assigned elsewhere)
|
210
|
+
options[:auto_assign] ||= 'commit'
|
211
|
+
options[:auto_assign] = nil if in_foreign_key
|
212
|
+
options[:mandatory] = path_mandatory
|
213
|
+
[ type_name, options ]
|
202
214
|
|
203
|
-
when ValueField,
|
215
|
+
when ValidFrom, ValueField, Mapping
|
204
216
|
# Walk up the entity type identifiers (must be single-part) to a value type:
|
205
217
|
vt = self.object_type
|
206
218
|
while vt.is_a?(EntityType)
|
@@ -248,8 +260,6 @@ module ActiveFacts
|
|
248
260
|
merge!(value_constraint ? {value_constraint: value_constraint} : {})
|
249
261
|
]
|
250
262
|
|
251
|
-
when Injection
|
252
|
-
object_type.name
|
253
263
|
else
|
254
264
|
raise "Can't make a column from #{component}"
|
255
265
|
end
|
@@ -265,7 +275,7 @@ end
|
|
265
275
|
|
266
276
|
if $0 == __FILE__
|
267
277
|
D = ActiveFacts::Metamodel::DataType
|
268
|
-
D.
|
278
|
+
D.intrinsic_type('Auto Timestamp')
|
269
279
|
|
270
280
|
class ModContext < D::DefaultContext
|
271
281
|
def integer_ranges
|
@@ -277,5 +287,5 @@ if $0 == __FILE__
|
|
277
287
|
end
|
278
288
|
end
|
279
289
|
puts "Normalising a tiny"
|
280
|
-
p D.
|
290
|
+
p D.choose_integer('tiny', nil, nil, ModContext.new)
|
281
291
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'pp'
|
2
1
|
#
|
3
2
|
# ActiveFacts Vocabulary Metamodel.
|
4
3
|
# Extensions to the ActiveFacts Vocabulary classes (which are generated from the Metamodel)
|
@@ -534,6 +533,33 @@ module ActiveFacts
|
|
534
533
|
end
|
535
534
|
nil
|
536
535
|
end
|
536
|
+
|
537
|
+
def all_value_type_parameter_transitive
|
538
|
+
supertypes_transitive.flat_map{|st| st.all_value_type_parameter.to_a}
|
539
|
+
end
|
540
|
+
|
541
|
+
def applicable_parameter_restrictions parameter_name, include_base_type = false
|
542
|
+
vtp = all_value_type_parameter_transitive.detect{|vtp| vtp.name == parameter_name }
|
543
|
+
return [] if !vtp || vtp.value_type == self
|
544
|
+
vtpr = all_value_type_parameter_restriction.select{|vtpr| vtpr.value_type_parameter == vtp }
|
545
|
+
if vtpr.empty?
|
546
|
+
supertype.applicable_parameter_restrictions parameter_name
|
547
|
+
else
|
548
|
+
vtpr
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
class ValueTypeParameter
|
554
|
+
def describe
|
555
|
+
"ValueType '#{value_type.name}' Parameter '#{name}' is of type '#{parameter_value_type.name}'"
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
class ValueTypeParameterRestriction
|
560
|
+
def inspect
|
561
|
+
value_range.inspect
|
562
|
+
end
|
537
563
|
end
|
538
564
|
|
539
565
|
class EntityType
|
@@ -555,101 +581,8 @@ module ActiveFacts
|
|
555
581
|
assimilation == 'partitioned'
|
556
582
|
end
|
557
583
|
|
558
|
-
def new_pi
|
559
|
-
trace :newpi, "Looking for New PI for #{name}" do
|
560
|
-
# An objectified fact type is identified by the object which plays it.
|
561
|
-
if fact_type && fact_type.all_role.size == 1
|
562
|
-
# REVISIT: If the OFT is separate (is this even possible?), this probably won't work:
|
563
|
-
return fact_type.all_role.single.object_type.preferred_identifier
|
564
|
-
end
|
565
|
-
|
566
|
-
# All roles in a preferred identifier must be a counterpart
|
567
|
-
# to a role played by this type or any of its supertypes.
|
568
|
-
# Here, a unary role is deemed to be its own counterpart.
|
569
|
-
# If this is an objectified fact type, its roles are deemed
|
570
|
-
# to be counterparts per virtue of the mirror role.
|
571
|
-
|
572
|
-
# if name == 'User'
|
573
|
-
# pp all_role_transitive.map{|a| a.fact_type.describe(a)}
|
574
|
-
# debugger
|
575
|
-
# end
|
576
|
-
|
577
|
-
art = all_role_transitive.map do |role|
|
578
|
-
# No TypeInheritance roles unless we play the subtype
|
579
|
-
if (ti = role.fact_type).is_a?(TypeInheritance) && role != ti.subtype_role
|
580
|
-
nil
|
581
|
-
elsif role.is_a?(MirrorRole)
|
582
|
-
nil
|
583
|
-
elsif role.fact_type.all_role.size == 1
|
584
|
-
role.base_role
|
585
|
-
else
|
586
|
-
x = (c = role.counterpart and c.base_role)
|
587
|
-
# debugger if x && x.object_type == self
|
588
|
-
x
|
589
|
-
end
|
590
|
-
end.compact
|
591
|
-
|
592
|
-
all_role.each do |role|
|
593
|
-
# Is this the subtype role in a supertype that identifies us?
|
594
|
-
if (ti = role.base_role.fact_type).is_a?(TypeInheritance)
|
595
|
-
if role == ti.subtype_role and ti.provides_identification
|
596
|
-
trace :newpi, "#{name} is identified by supertype #{ti.supertype.name}"
|
597
|
-
|
598
|
-
pcs = ti.supertype_role.all_role_ref.to_a.flat_map(&:role_sequence).flat_map(&:all_presence_constraint).to_a
|
599
|
-
debugger if pcs.size > 1
|
600
|
-
return pcs[0]
|
601
|
-
|
602
|
-
return ti.supertype_role.object_type.preferred_identifier
|
603
|
-
end
|
604
|
-
next # It can't be this TypeInheritance
|
605
|
-
end
|
606
|
-
|
607
|
-
# The fact type must be binary or unary
|
608
|
-
next if role.fact_type.all_role.size > 2
|
609
|
-
|
610
|
-
base_role = role.counterpart.base_role # Go to the OFT role that implied the link fact type
|
611
|
-
base_role.all_role_ref.each do |rr|
|
612
|
-
if rr.role_sequence.all_presence_constraint.size > 0
|
613
|
-
trace :newpi, "Looking for New PI that includes '#{base_role.fact_type.describe(base_role)}'"
|
614
|
-
end
|
615
|
-
rr.role_sequence.all_presence_constraint.each do |pc|
|
616
|
-
next unless pc.max_frequency == 1 and
|
617
|
-
pc.is_preferred_identifier and
|
618
|
-
!pc.enforcement # Alethic uniqueness constraint
|
619
|
-
# We have a uniqueness constraint that is alethic and preferred.
|
620
|
-
# If all its role are valid counterparts, this is our preferred identifier.
|
621
|
-
next if pc.role_sequence.all_role_ref.to_a.detect do |nrr|
|
622
|
-
if !art.include?(nrr.role)
|
623
|
-
trace :newpi, "Rejecting New PI with excluded role '#{nrr.role.fact_type.describe(nrr.role)}'"
|
624
|
-
end
|
625
|
-
!art.include?(nrr.role) # Nope, not included in the valid counterparts
|
626
|
-
end
|
627
|
-
trace :newpi, "Accepting New PI #{pc.describe}"
|
628
|
-
return pc
|
629
|
-
end
|
630
|
-
end
|
631
|
-
end
|
632
|
-
|
633
|
-
debugger
|
634
|
-
trace :newpi, "No New PI found for #{name}"
|
635
|
-
nil
|
636
|
-
|
637
|
-
end
|
638
|
-
end
|
639
|
-
|
640
584
|
def preferred_identifier
|
641
585
|
return @preferred_identifier if @preferred_identifier
|
642
|
-
|
643
|
-
@old_preferred_identifier = old_preferred_identifier
|
644
|
-
# @new_preferred_identifier = new_pi
|
645
|
-
# if @old_preferred_identifier != @new_preferred_identifier
|
646
|
-
## debugger
|
647
|
-
# new_pi
|
648
|
-
# end
|
649
|
-
return @preferred_identifier = @old_preferred_identifier
|
650
|
-
end
|
651
|
-
|
652
|
-
def old_preferred_identifier
|
653
586
|
if fact_type
|
654
587
|
# Objectified unaries are identified by the ID of the object that plays the role:
|
655
588
|
if fact_type.all_role.size == 1
|
@@ -1101,11 +1034,17 @@ module ActiveFacts
|
|
1101
1034
|
|
1102
1035
|
class AllowedRange
|
1103
1036
|
def to_s(infinity = true)
|
1104
|
-
|
1105
|
-
|
1037
|
+
value_range.to_s infinity
|
1038
|
+
end
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
class ValueRange
|
1042
|
+
def to_s(infinity = true)
|
1043
|
+
min = minimum_bound
|
1044
|
+
max = maximum_bound
|
1106
1045
|
# Open-ended string ranges will fail in Ruby
|
1107
1046
|
|
1108
|
-
if min =
|
1047
|
+
if min = minimum_bound
|
1109
1048
|
min = min.value
|
1110
1049
|
if min.is_literal_string
|
1111
1050
|
min_literal = min.literal.inspect.gsub(/\A"|"\Z/,"'") # Escape string characters
|
@@ -1115,7 +1054,7 @@ module ActiveFacts
|
|
1115
1054
|
else
|
1116
1055
|
min_literal = infinity ? "-Infinity" : ""
|
1117
1056
|
end
|
1118
|
-
if max =
|
1057
|
+
if max = maximum_bound
|
1119
1058
|
max = max.value
|
1120
1059
|
if max.is_literal_string
|
1121
1060
|
max_literal = max.literal.inspect.gsub(/\A"|"\Z/,"'") # Escape string characters
|
@@ -1129,6 +1068,40 @@ module ActiveFacts
|
|
1129
1068
|
min_literal +
|
1130
1069
|
(min_literal != (max&&max_literal) ? (".." + max_literal) : "")
|
1131
1070
|
end
|
1071
|
+
|
1072
|
+
def inspect
|
1073
|
+
to_s
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
# Note the mismatched return types here:
|
1077
|
+
def effective_maximum
|
1078
|
+
maximum_bound ? maximum_bound.value : Infinity
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
def effective_minimum
|
1082
|
+
minimum_bound ? minimum_bound.value : -Infinity
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
def includes? range
|
1086
|
+
if ValueRange === range
|
1087
|
+
range.effective_minimum >= effective_minimum && range.effective_maximum <= effective_maximum
|
1088
|
+
# elsif Bound === range # REVISIT: use self.includes?(range.value) with is_literal_string, etc
|
1089
|
+
else
|
1090
|
+
range >= effective_minimum && range <= effective_maximum
|
1091
|
+
end
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
class Bound
|
1096
|
+
def <=(other)
|
1097
|
+
return true if other == Infinity
|
1098
|
+
is_inclusive ? value <= other : value < other
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
def >=(other)
|
1102
|
+
return true if other == -Infinity
|
1103
|
+
is_inclusive ? value >= other : value > other
|
1104
|
+
end
|
1132
1105
|
end
|
1133
1106
|
|
1134
1107
|
class Value
|
@@ -1149,6 +1122,38 @@ module ActiveFacts
|
|
1149
1122
|
def inspect
|
1150
1123
|
to_s
|
1151
1124
|
end
|
1125
|
+
|
1126
|
+
def effective_value
|
1127
|
+
is_literal_string ? literal : eval(literal)
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
def ==(other)
|
1131
|
+
effective_value == (Value === other ? other.effective_value : other)
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
def !=(other)
|
1135
|
+
!(self == other)
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
def <=(other)
|
1139
|
+
return true if other == Infinity
|
1140
|
+
effective_value <= other.effective_value rescue nil
|
1141
|
+
end
|
1142
|
+
|
1143
|
+
def >=(other)
|
1144
|
+
return true if other == -Infinity
|
1145
|
+
effective_value >= other.effective_value rescue nil
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
def <(other)
|
1149
|
+
v = self >= other
|
1150
|
+
v == nil ? v : !v
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
def >(other)
|
1154
|
+
v = self >= other
|
1155
|
+
v == nil ? v : !v
|
1156
|
+
end
|
1152
1157
|
end
|
1153
1158
|
|
1154
1159
|
class PresenceConstraint
|
@@ -1671,7 +1676,7 @@ module ActiveFacts
|
|
1671
1676
|
|
1672
1677
|
inbound = all_access_path.
|
1673
1678
|
select{|ap| ap.is_a?(ForeignKey)}.
|
1674
|
-
sort_by{|fk| [fk.source_composite.mapping.name, fk.
|
1679
|
+
sort_by{|fk| [fk.source_composite.mapping.name, fk.mapping.inspect]+fk.all_foreign_key_field.map(&:inspect)+fk.all_index_field.map(&:inspect) }
|
1675
1680
|
unless inbound.empty?
|
1676
1681
|
trace :composition, "Foreign keys inbound" do
|
1677
1682
|
inbound.each do |fk|
|
@@ -1682,7 +1687,7 @@ module ActiveFacts
|
|
1682
1687
|
|
1683
1688
|
outbound =
|
1684
1689
|
all_foreign_key_as_source_composite.
|
1685
|
-
sort_by{|fk| [fk.source_composite.mapping.name, fk.
|
1690
|
+
sort_by{|fk| [fk.source_composite.mapping.name, fk.mapping.inspect]+fk.all_index_field.map(&:inspect)+fk.all_foreign_key_field.map(&:inspect) }
|
1686
1691
|
unless outbound.empty?
|
1687
1692
|
trace :composition, "Foreign keys outbound" do
|
1688
1693
|
outbound.each do |fk|
|
@@ -1697,7 +1702,7 @@ module ActiveFacts
|
|
1697
1702
|
def all_indices_by_rank
|
1698
1703
|
all_access_path.
|
1699
1704
|
reject{|ap| ap.is_a?(ActiveFacts::Metamodel::ForeignKey)}.
|
1700
|
-
sort_by{|ap| ap.all_index_field.to_a.flat_map{|ixf| ixf.component.rank_path}.compact }
|
1705
|
+
sort_by{|ap| ap.all_index_field.to_a.flat_map{|ixf| (c = ixf.component) ? c.rank_path : 0}.compact }
|
1701
1706
|
end
|
1702
1707
|
|
1703
1708
|
def all_foreign_key_as_target_composite
|
@@ -1736,12 +1741,14 @@ module ActiveFacts
|
|
1736
1741
|
'Non-unique index'
|
1737
1742
|
when composite_as_primary_index
|
1738
1743
|
'Primary index'
|
1744
|
+
when composite_as_natural_index
|
1745
|
+
'Natural index'
|
1739
1746
|
else
|
1740
1747
|
'Unique index'
|
1741
1748
|
end +
|
1742
1749
|
(name ? " #{name.inspect}" : '') +
|
1743
1750
|
" to #{composite.mapping.name}" +
|
1744
|
-
(presence_constraint ? "
|
1751
|
+
(presence_constraint ? "#{presence_constraint.role_sequence.describe}" : '')
|
1745
1752
|
end
|
1746
1753
|
end
|
1747
1754
|
|
@@ -1750,13 +1757,14 @@ module ActiveFacts
|
|
1750
1757
|
"Foreign Key" +
|
1751
1758
|
(name ? " #{name.inspect}" : '') +
|
1752
1759
|
" from #{(sc = source_composite) ? sc.mapping.name : 'NO-SOURCE'} to #{composite.mapping.name}" +
|
1753
|
-
(
|
1760
|
+
(mapping ? " over #{mapping.inspect}" : '')
|
1754
1761
|
end
|
1755
1762
|
end
|
1756
1763
|
|
1757
1764
|
class IndexField
|
1758
1765
|
def inspect
|
1759
|
-
|
1766
|
+
c_name = component ? component.root.mapping.name : "WARNING: IndexField without Component"
|
1767
|
+
"IndexField part #{ordinal} in #{c_name} references #{component.inspect}" +
|
1760
1768
|
(value ? " discriminated by #{value.inspect}" : '')
|
1761
1769
|
end
|
1762
1770
|
end
|
@@ -1770,6 +1778,10 @@ module ActiveFacts
|
|
1770
1778
|
end
|
1771
1779
|
|
1772
1780
|
class Mapping
|
1781
|
+
def inspect_reason
|
1782
|
+
"#{parent.name} contains mapping of #{name}"
|
1783
|
+
end
|
1784
|
+
|
1773
1785
|
def inspect
|
1774
1786
|
"#{self.class.basename} (#{rank_kind})#{parent ? " in #{parent.name}" :''} of #{name && name != '' ? name : '<anonymous>'}"
|
1775
1787
|
end
|
@@ -1777,12 +1789,20 @@ module ActiveFacts
|
|
1777
1789
|
def show_trace
|
1778
1790
|
trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect}" do
|
1779
1791
|
yield if block_given?
|
1792
|
+
if m = all_member.detect{|m| !m.ordinal}
|
1793
|
+
trace :composition, "WARNING: show_trace needed to re_rank #{name} because of unranked #{m.inspect}"
|
1794
|
+
re_rank
|
1795
|
+
end
|
1780
1796
|
all_member.sort_by{|member| [member.ordinal, member.name]}.each do |member|
|
1781
1797
|
member.show_trace
|
1782
1798
|
end
|
1783
1799
|
end
|
1784
1800
|
end
|
1785
1801
|
|
1802
|
+
def is_type_inheritance
|
1803
|
+
false
|
1804
|
+
end
|
1805
|
+
|
1786
1806
|
# Recompute a contiguous member ranking fron zero, based on current membership:
|
1787
1807
|
def re_rank
|
1788
1808
|
all_member.each(&:uncache_rank_key)
|
@@ -1815,7 +1835,7 @@ module ActiveFacts
|
|
1815
1835
|
end
|
1816
1836
|
|
1817
1837
|
def path_mandatory
|
1818
|
-
|
1838
|
+
!parent || parent.path_mandatory
|
1819
1839
|
end
|
1820
1840
|
|
1821
1841
|
def is_auto_assigned
|
@@ -1829,6 +1849,10 @@ module ActiveFacts
|
|
1829
1849
|
nil
|
1830
1850
|
end
|
1831
1851
|
end
|
1852
|
+
|
1853
|
+
def is_partitioned_here
|
1854
|
+
false # Must be an absorption to be partitioned here
|
1855
|
+
end
|
1832
1856
|
end
|
1833
1857
|
|
1834
1858
|
class Nesting
|
@@ -1840,19 +1864,19 @@ module ActiveFacts
|
|
1840
1864
|
end
|
1841
1865
|
|
1842
1866
|
class Absorption
|
1843
|
-
def
|
1867
|
+
def inspect_reason
|
1844
1868
|
parent_role.fact_type.reading_preferably_starting_with_role(parent_role).expand.inspect
|
1845
1869
|
end
|
1846
1870
|
|
1847
1871
|
def inspect
|
1848
1872
|
"#{super}#{full_absorption ? ' (full)' : ''
|
1849
|
-
} in #{
|
1873
|
+
} in #{inspect_reason}#{
|
1850
1874
|
# If we have a related forward absorption, we're by definition a reverse absorption
|
1851
|
-
if
|
1875
|
+
if forward_mapping
|
1852
1876
|
' (reverse)'
|
1853
1877
|
else
|
1854
1878
|
# If we have a related reverse absorption, we're by definition a forward absorption
|
1855
|
-
|
1879
|
+
reverse_mapping ? ' (forward)' : ''
|
1856
1880
|
end
|
1857
1881
|
}"
|
1858
1882
|
end
|
@@ -1879,6 +1903,14 @@ module ActiveFacts
|
|
1879
1903
|
is_type_inheritance && parent_role.fact_type.supertype == object_type
|
1880
1904
|
end
|
1881
1905
|
|
1906
|
+
def is_partitioned_here
|
1907
|
+
(ft = child_role.fact_type).is_a?(TypeInheritance) && ft.assimilation == 'partitioned'
|
1908
|
+
end
|
1909
|
+
|
1910
|
+
def is_one_to_one
|
1911
|
+
parent_role.is_unique and child_role.is_unique
|
1912
|
+
end
|
1913
|
+
|
1882
1914
|
def is_preferred_direction
|
1883
1915
|
return child_role.is_mirror_role if child_role.is_mirror_role != parent_role.is_mirror_role
|
1884
1916
|
|
@@ -1932,15 +1964,15 @@ module ActiveFacts
|
|
1932
1964
|
end
|
1933
1965
|
|
1934
1966
|
def flip!
|
1935
|
-
raise "REVISIT: Need to flip FullAbsorption on #{inspect}" if full_absorption or
|
1936
|
-
if (other =
|
1967
|
+
raise "REVISIT: Need to flip FullAbsorption on #{inspect}" if full_absorption or reverse_mapping && reverse_mapping.full_absorption or forward_mapping && forward_mapping.full_absorption
|
1968
|
+
if (other = forward_mapping)
|
1937
1969
|
# We point at them - make them point at us instead
|
1938
|
-
self.
|
1939
|
-
self.
|
1940
|
-
elsif (other =
|
1970
|
+
self.forward_mapping = nil
|
1971
|
+
self.reverse_mapping = other
|
1972
|
+
elsif (other = reverse_mapping)
|
1941
1973
|
# They point at us - make us point at them instead
|
1942
|
-
self.
|
1943
|
-
self.
|
1974
|
+
self.reverse_mapping = nil
|
1975
|
+
self.forward_mapping = other
|
1944
1976
|
else
|
1945
1977
|
raise "Absorption cannot be flipped as it has no reverse"
|
1946
1978
|
end
|
@@ -2053,8 +2085,10 @@ module ActiveFacts
|
|
2053
2085
|
when SurrogateKey
|
2054
2086
|
if is_identifying
|
2055
2087
|
[RANK_SURROGATE] # an injected PK
|
2088
|
+
elsif injection_annotation
|
2089
|
+
[RANK_INJECTION, name]
|
2056
2090
|
else
|
2057
|
-
[
|
2091
|
+
[RANK_FOREIGN, name] # an FK
|
2058
2092
|
end
|
2059
2093
|
|
2060
2094
|
when Indicator
|
@@ -2070,10 +2104,11 @@ module ActiveFacts
|
|
2070
2104
|
[RANK_DISCRIMINATOR, name || child_role.name]
|
2071
2105
|
|
2072
2106
|
when ValueField
|
2073
|
-
|
2074
|
-
|
2075
|
-
|
2076
|
-
|
2107
|
+
if injection_annotation
|
2108
|
+
[RANK_INJECTION, name]
|
2109
|
+
else
|
2110
|
+
[RANK_IDENT]
|
2111
|
+
end
|
2077
2112
|
|
2078
2113
|
when Absorption
|
2079
2114
|
if is_type_inheritance
|
@@ -2089,6 +2124,8 @@ module ActiveFacts
|
|
2089
2124
|
end
|
2090
2125
|
elsif (p = parent_entity_type) and (position = p.rank_in_preferred_identifier(child_role.base_role))
|
2091
2126
|
[RANK_IDENT, position]
|
2127
|
+
elsif injection_annotation
|
2128
|
+
[RANK_INJECTION, name]
|
2092
2129
|
else
|
2093
2130
|
if parent_role.is_unique
|
2094
2131
|
[parent_role.is_mandatory ? RANK_MANDATORY : RANK_NON_MANDATORY, name || child_role.name]
|
@@ -2100,8 +2137,16 @@ module ActiveFacts
|
|
2100
2137
|
when Scoping
|
2101
2138
|
[RANK_SCOPING, name || object_type.name]
|
2102
2139
|
|
2140
|
+
when ValidFrom
|
2141
|
+
[RANK_INJECTION, name]
|
2142
|
+
|
2103
2143
|
when Mapping
|
2104
|
-
|
2144
|
+
# bare Mappings are always injected
|
2145
|
+
if root.mapping.object_type == object_type
|
2146
|
+
[RANK_IDENT, 0]
|
2147
|
+
else
|
2148
|
+
[RANK_INJECTION, name]
|
2149
|
+
end
|
2105
2150
|
|
2106
2151
|
else
|
2107
2152
|
raise "unexpected #{self.class.basename} in Component#rank_key"
|
@@ -2118,6 +2163,10 @@ module ActiveFacts
|
|
2118
2163
|
ixfs.map(&:component)
|
2119
2164
|
end
|
2120
2165
|
|
2166
|
+
def is_in_primary
|
2167
|
+
!!(root and p = root.primary_index and p.all_index_field.detect{|f| f.component == self})
|
2168
|
+
end
|
2169
|
+
|
2121
2170
|
def parent_entity_type
|
2122
2171
|
parent &&
|
2123
2172
|
parent.object_type.is_a?(EntityType) &&
|
@@ -2195,7 +2244,7 @@ module ActiveFacts
|
|
2195
2244
|
end
|
2196
2245
|
|
2197
2246
|
def fork_to_new_parent parent
|
2198
|
-
@constellation.fork self, guid: :new, parent: parent
|
2247
|
+
@constellation.fork self, guid: :new, parent: parent, injection_annotation: nil
|
2199
2248
|
end
|
2200
2249
|
end
|
2201
2250
|
|
@@ -2205,12 +2254,6 @@ module ActiveFacts
|
|
2205
2254
|
end
|
2206
2255
|
end
|
2207
2256
|
|
2208
|
-
class Injection
|
2209
|
-
def path_mandatory
|
2210
|
-
parent.path_mandatory
|
2211
|
-
end
|
2212
|
-
end
|
2213
|
-
|
2214
2257
|
class ValueField
|
2215
2258
|
def inspect
|
2216
2259
|
"#{self.class.basename} #{object_type.name.inspect}"
|
@@ -2226,7 +2269,7 @@ module ActiveFacts
|
|
2226
2269
|
|
2227
2270
|
def fork_to_new_parent parent
|
2228
2271
|
# When we fork from a ValueField, we want to use the name of the ValueType, not the ValueField name
|
2229
|
-
@constellation.fork self, guid: :new, parent: parent, name: object_type.name
|
2272
|
+
@constellation.fork self, guid: :new, parent: parent, name: object_type.name, injection_annotation: nil
|
2230
2273
|
end
|
2231
2274
|
end
|
2232
2275
|
|
@@ -2254,6 +2297,14 @@ module ActiveFacts
|
|
2254
2297
|
end
|
2255
2298
|
(parent ? parent.name + ' ' : '') + 'surrogate key'
|
2256
2299
|
end
|
2300
|
+
|
2301
|
+
def inspect
|
2302
|
+
"#{self.class.basename} (#{rank_kind})#{parent ? " in #{parent.name}" :''} of #{name && name != '' ? name : '<anonymous>'}"
|
2303
|
+
end
|
2304
|
+
|
2305
|
+
def show_trace
|
2306
|
+
trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect}"
|
2307
|
+
end
|
2257
2308
|
end
|
2258
2309
|
|
2259
2310
|
#
|