ecs_on_rails 0.2.2 → 0.3.0
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/CHANGELOG.md +304 -0
- data/README.md +365 -50
- data/lib/ecs_rails/catalogue/address.rb +39 -0
- data/lib/ecs_rails/catalogue/calendar_date.rb +27 -0
- data/lib/ecs_rails/catalogue/counter.rb +46 -0
- data/lib/ecs_rails/catalogue/discard.rb +36 -0
- data/lib/ecs_rails/catalogue/email.rb +35 -0
- data/lib/ecs_rails/catalogue/geolocation.rb +53 -0
- data/lib/ecs_rails/catalogue/identifier.rb +23 -0
- data/lib/ecs_rails/catalogue/image.rb +28 -0
- data/lib/ecs_rails/catalogue/link.rb +27 -0
- data/lib/ecs_rails/catalogue/marker.rb +38 -0
- data/lib/ecs_rails/catalogue/money.rb +86 -0
- data/lib/ecs_rails/catalogue/name.rb +37 -0
- data/lib/ecs_rails/catalogue/password.rb +50 -0
- data/lib/ecs_rails/catalogue/period.rb +57 -0
- data/lib/ecs_rails/catalogue/phone.rb +30 -0
- data/lib/ecs_rails/catalogue/position.rb +18 -0
- data/lib/ecs_rails/catalogue/rating.rb +25 -0
- data/lib/ecs_rails/catalogue/relationship.rb +159 -0
- data/lib/ecs_rails/catalogue/role.rb +23 -0
- data/lib/ecs_rails/catalogue/schema_diff.rb +198 -0
- data/lib/ecs_rails/catalogue/search_vector.rb +38 -0
- data/lib/ecs_rails/catalogue/state.rb +71 -0
- data/lib/ecs_rails/catalogue/tags.rb +64 -0
- data/lib/ecs_rails/catalogue/text.rb +29 -0
- data/lib/ecs_rails/catalogue/timestamp.rb +34 -0
- data/lib/ecs_rails/catalogue/token.rb +77 -0
- data/lib/ecs_rails/catalogue.rb +405 -0
- data/lib/ecs_rails/component.rb +13 -7
- data/lib/ecs_rails/config.rb +33 -11
- data/lib/ecs_rails/dsl.rb +463 -97
- data/lib/ecs_rails/entity.rb +21 -5
- data/lib/ecs_rails/errors.rb +3 -0
- data/lib/ecs_rails/inverses.rb +398 -0
- data/lib/ecs_rails/lazy.rb +86 -23
- data/lib/ecs_rails/markers.rb +197 -0
- data/lib/ecs_rails/preloading.rb +19 -8
- data/lib/ecs_rails/presence.rb +83 -30
- data/lib/ecs_rails/querying.rb +158 -12
- data/lib/ecs_rails/railtie.rb +10 -0
- data/lib/ecs_rails/registry.rb +66 -21
- data/lib/ecs_rails/relationships.rb +168 -160
- data/lib/ecs_rails/slots.rb +183 -0
- data/lib/ecs_rails/validations.rb +3 -5
- data/lib/ecs_rails/version.rb +2 -2
- data/lib/ecs_rails.rb +7 -3
- data/lib/generators/ecs_rails/catalogue_options.rb +66 -0
- data/lib/generators/ecs_rails/component/templates/migration.rb.tt +9 -5
- data/lib/generators/ecs_rails/component/templates/model.rb.tt +2 -1
- data/lib/generators/ecs_rails/entity/entity_generator.rb +93 -0
- data/lib/generators/ecs_rails/entity/templates/entity.rb.tt +9 -0
- data/lib/generators/ecs_rails/install/install_generator.rb +29 -12
- data/lib/generators/ecs_rails/install/templates/application_component.rb.tt +3 -2
- data/lib/generators/ecs_rails/install/templates/application_entity.rb.tt +2 -2
- data/lib/generators/ecs_rails/install/templates/initializer.rb.tt +2 -2
- data/lib/generators/ecs_rails/install/templates/install_migration.rb.tt +38 -0
- data/lib/generators/ecs_rails/templates/catalogue_class.rb.tt +10 -0
- data/lib/generators/ecs_rails/upgrade/templates/catalogue_migration.rb.tt +18 -0
- data/lib/generators/ecs_rails/upgrade/templates/markers_migration.rb.tt +31 -0
- data/lib/generators/ecs_rails/upgrade/templates/relationships_migration.rb.tt +33 -0
- data/lib/generators/ecs_rails/upgrade/templates/slots_migration.rb.tt +23 -0
- data/lib/generators/ecs_rails/upgrade/upgrade_generator.rb +281 -0
- metadata +61 -4
- data/lib/generators/ecs_rails/install/templates/migration.rb.tt +0 -20
- data/lib/generators/ecs_rails/relationship/relationship_generator.rb +0 -99
- data/lib/generators/ecs_rails/relationship/templates/migration.rb.tt +0 -32
data/lib/ecs_rails/railtie.rb
CHANGED
|
@@ -10,5 +10,15 @@ module EcsRails
|
|
|
10
10
|
config.to_prepare do
|
|
11
11
|
EcsRails.registry.clear! if EcsRails.registry.respond_to?(:clear!)
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
# Inverse relationships (RFC-0015) are validated on first use because
|
|
15
|
+
# checking at class-load time is unsafe under autoloading. When the app
|
|
16
|
+
# eager-loads — production — every entity is present at boot, so check them
|
|
17
|
+
# all now and fail to start rather than at the first request.
|
|
18
|
+
config.after_initialize do |app|
|
|
19
|
+
next unless app.config.eager_load
|
|
20
|
+
|
|
21
|
+
EcsRails::Entity.descendants.reject(&:abstract_class?).each(&:validate_inverses!)
|
|
22
|
+
end
|
|
13
23
|
end
|
|
14
24
|
end
|
data/lib/ecs_rails/registry.rb
CHANGED
|
@@ -20,7 +20,9 @@ module EcsRails
|
|
|
20
20
|
# nothing here stores a Class: entries are keyed by class *name*, and names are
|
|
21
21
|
# resolved back to live constants via #constantize at read time.
|
|
22
22
|
class Registry
|
|
23
|
-
# One `component Foo` declaration on one entity class
|
|
23
|
+
# One `component Foo` declaration on one entity class — under one slot
|
|
24
|
+
# (RFC-0014 / ADR-0015): the same component declared twice under different
|
|
25
|
+
# labels is two Declarations.
|
|
24
26
|
#
|
|
25
27
|
# A value object over *names*. #entity_class / #component_class resolve on
|
|
26
28
|
# every call, so a Declaration handed out before a reload still resolves to
|
|
@@ -30,20 +32,50 @@ module EcsRails
|
|
|
30
32
|
# @return [String] the declaring entity's class name
|
|
31
33
|
# @!attribute [r] component_class_name
|
|
32
34
|
# @return [String] the declared component's class name
|
|
35
|
+
# @!attribute [r] slot
|
|
36
|
+
# @return [String] the slot label; `""` is the default (singular) slot
|
|
33
37
|
# @!attribute [r] options
|
|
34
|
-
# @return [Hash] the frozen `only:`/`except:`
|
|
35
|
-
|
|
38
|
+
# @return [Hash] the frozen delegation options: `only:`/`except:` as
|
|
39
|
+
# symbol arrays, `prefix: false` for bare delegation (ADR-0016), and
|
|
40
|
+
# `delegate: false` for none (RFC-0014). `{}` means everything
|
|
41
|
+
# delegated, reader-prefixed.
|
|
42
|
+
# @!attribute [r] slot_options
|
|
43
|
+
# @return [Hash{Symbol => Object}] the frozen per-slot options the
|
|
44
|
+
# declaration passed through to the component (RFC-0014, e.g.
|
|
45
|
+
# `states: %w[...]`); see {EcsRails::Slots::Component#slot_options}
|
|
46
|
+
attr_reader :entity_class_name, :component_class_name, :slot, :options, :slot_options
|
|
36
47
|
|
|
37
48
|
# @param entity_class_name [String] the declaring entity's class name
|
|
38
49
|
# @param component_class_name [String] the declared component's class name
|
|
39
|
-
# @param
|
|
40
|
-
|
|
50
|
+
# @param slot [String] the slot label, `""` for the default slot
|
|
51
|
+
# @param options [Hash] `only:`/`except:`/`prefix:`/`delegate:` delegation options
|
|
52
|
+
# @param slot_options [Hash] per-slot options passed through to the component
|
|
53
|
+
def initialize(entity_class_name:, component_class_name:, slot: "", options: {}, slot_options: {})
|
|
41
54
|
@entity_class_name = entity_class_name
|
|
42
55
|
@component_class_name = component_class_name
|
|
56
|
+
@slot = slot.to_s.dup.freeze
|
|
43
57
|
@options = options.dup.freeze
|
|
58
|
+
@slot_options = slot_options.dup.freeze
|
|
44
59
|
freeze
|
|
45
60
|
end
|
|
46
61
|
|
|
62
|
+
# The entity reader this declaration generates — `postal_address` for the
|
|
63
|
+
# default slot, `business_address` for slot `"business"`. Derived by
|
|
64
|
+
# {EcsRails::Slots::Component::ClassMethods#ecs_reader_name} so the
|
|
65
|
+
# component instance and the declaration cannot disagree.
|
|
66
|
+
#
|
|
67
|
+
# @return [Symbol]
|
|
68
|
+
def reader_name
|
|
69
|
+
component_class.ecs_reader_name(slot)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [Symbol, nil] the slot as the `prefix:` keyword the DSL was given,
|
|
73
|
+
# or nil for the default slot — the form {EcsRails::Presence::Entity#has?}
|
|
74
|
+
# and {EcsRails::DSL#declaration_for} take
|
|
75
|
+
def prefix
|
|
76
|
+
slot.empty? ? nil : slot.to_sym
|
|
77
|
+
end
|
|
78
|
+
|
|
47
79
|
# Resolved live, so a reloaded constant is picked up.
|
|
48
80
|
#
|
|
49
81
|
# @return [Class<EcsRails::Entity>] the declaring entity class
|
|
@@ -62,24 +94,28 @@ module EcsRails
|
|
|
62
94
|
|
|
63
95
|
# @param other [Object]
|
|
64
96
|
# @return [Boolean] true if both declare the same component on the same
|
|
65
|
-
# entity with the same options
|
|
97
|
+
# entity, in the same slot, with the same options
|
|
66
98
|
def ==(other)
|
|
67
99
|
other.is_a?(Declaration) &&
|
|
68
100
|
entity_class_name == other.entity_class_name &&
|
|
69
101
|
component_class_name == other.component_class_name &&
|
|
70
|
-
|
|
102
|
+
slot == other.slot &&
|
|
103
|
+
options == other.options &&
|
|
104
|
+
slot_options == other.slot_options
|
|
71
105
|
end
|
|
72
106
|
alias eql? ==
|
|
73
107
|
|
|
74
108
|
# @return [Integer] a hash consistent with {#==}, so Declarations work as
|
|
75
109
|
# Hash keys and in Sets
|
|
76
110
|
def hash
|
|
77
|
-
[self.class, entity_class_name, component_class_name, options].hash
|
|
111
|
+
[self.class, entity_class_name, component_class_name, slot, options, slot_options].hash
|
|
78
112
|
end
|
|
79
113
|
|
|
80
|
-
# @return [String] e.g. `#<...Declaration User => Email {}>`
|
|
114
|
+
# @return [String] e.g. `#<...Declaration User => Email {}>` or
|
|
115
|
+
# `#<...Declaration User => PostalAddress[business] {}>`
|
|
81
116
|
def inspect
|
|
82
|
-
|
|
117
|
+
label = slot.empty? ? "" : "[#{slot}]"
|
|
118
|
+
"#<#{self.class} #{entity_class_name} => #{component_class_name}#{label} #{options.inspect}>"
|
|
83
119
|
end
|
|
84
120
|
end
|
|
85
121
|
|
|
@@ -89,33 +125,41 @@ module EcsRails
|
|
|
89
125
|
|
|
90
126
|
# Records one declaration. Returns the Declaration.
|
|
91
127
|
#
|
|
92
|
-
# Raises DuplicateComponent if this entity already declares this component
|
|
93
|
-
# per ADR-0005
|
|
94
|
-
#
|
|
128
|
+
# Raises DuplicateComponent if this entity already declares this component
|
|
129
|
+
# in this slot — per ADR-0005 as generalised by ADR-0015, a component appears
|
|
130
|
+
# at most once per (entity, slot), and RFC-0004 relies on the raise to catch
|
|
131
|
+
# a doubled `component` line at class-load time. The same component under a
|
|
132
|
+
# different slot is a distinct declaration.
|
|
95
133
|
#
|
|
96
134
|
# @param entity_class [Class<EcsRails::Entity>] the declaring entity
|
|
97
135
|
# @param component_class [Class<EcsRails::Component>] the declared component
|
|
98
|
-
# @param
|
|
136
|
+
# @param slot [String, Symbol] the slot label; `""` for the default slot
|
|
137
|
+
# @param options [Hash] `only:`/`except:`/`prefix:`/`delegate:` delegation options
|
|
138
|
+
# @param slot_options [Hash] per-slot options passed through to the component
|
|
99
139
|
# @return [Declaration] the recorded declaration
|
|
100
140
|
# @raise [EcsRails::DuplicateComponent] if this entity already declares this
|
|
101
|
-
# component (ADR-0005)
|
|
141
|
+
# component in this slot (ADR-0005 / ADR-0015)
|
|
102
142
|
# @raise [ArgumentError] if either class is anonymous, since the registry
|
|
103
143
|
# keys entries by class name
|
|
104
|
-
def register(entity_class:, component_class:, options: {})
|
|
144
|
+
def register(entity_class:, component_class:, slot: "", options: {}, slot_options: {})
|
|
105
145
|
entity_name = name_for(entity_class)
|
|
106
146
|
component_name = name_for(component_class)
|
|
147
|
+
slot = slot.to_s
|
|
107
148
|
|
|
108
149
|
declarations = (@declarations[entity_name] ||= [])
|
|
109
150
|
|
|
110
|
-
if declarations.any? { |
|
|
151
|
+
if declarations.any? { |d| d.component_class_name == component_name && d.slot == slot }
|
|
152
|
+
where = slot.empty? ? "" : " in slot #{slot.inspect} (prefix: :#{slot})"
|
|
111
153
|
raise DuplicateComponent,
|
|
112
|
-
"#{entity_name} already declares #{component_name}"
|
|
154
|
+
"#{entity_name} already declares #{component_name}#{where}"
|
|
113
155
|
end
|
|
114
156
|
|
|
115
157
|
declaration = Declaration.new(
|
|
116
158
|
entity_class_name: entity_name,
|
|
117
159
|
component_class_name: component_name,
|
|
118
|
-
|
|
160
|
+
slot: slot,
|
|
161
|
+
options: options,
|
|
162
|
+
slot_options: slot_options
|
|
119
163
|
)
|
|
120
164
|
declarations << declaration
|
|
121
165
|
declaration
|
|
@@ -140,7 +184,8 @@ module EcsRails
|
|
|
140
184
|
declarations ? declarations.dup : []
|
|
141
185
|
end
|
|
142
186
|
|
|
143
|
-
# Every entity class declaring this component, as live class objects.
|
|
187
|
+
# Every entity class declaring this component, as live class objects. An
|
|
188
|
+
# entity declaring it under two slots appears once.
|
|
144
189
|
#
|
|
145
190
|
# @param component_class [Class<EcsRails::Component>] the component
|
|
146
191
|
# @return [Array<Class<EcsRails::Entity>>] the entities composed from it
|
|
@@ -152,7 +197,7 @@ module EcsRails
|
|
|
152
197
|
declarations.each do |declaration|
|
|
153
198
|
entities << declaration.entity_class if declaration.component_class_name == component_name
|
|
154
199
|
end
|
|
155
|
-
end
|
|
200
|
+
end.uniq
|
|
156
201
|
end
|
|
157
202
|
|
|
158
203
|
# Resets the registry. Used between tests and by the Railtie's `to_prepare`.
|