isomorfeus-data 1.0.0.delta11
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +3 -0
- data/lib/isomorfeus/data/config.rb +116 -0
- data/lib/isomorfeus/data/core_ext/hash/deep_merge.rb +35 -0
- data/lib/isomorfeus/data/handler/array_load_handler.rb +41 -0
- data/lib/isomorfeus/data/handler/collection_load_handler.rb +42 -0
- data/lib/isomorfeus/data/handler/graph_load_handler.rb +42 -0
- data/lib/isomorfeus/data/handler/hash_load_handler.rb +41 -0
- data/lib/isomorfeus/data/prop_declaration.rb +58 -0
- data/lib/isomorfeus/data/props.rb +96 -0
- data/lib/isomorfeus/data/reducer.rb +30 -0
- data/lib/isomorfeus/data/version.rb +5 -0
- data/lib/isomorfeus-data.rb +48 -0
- data/lib/lucid_array/base.rb +15 -0
- data/lib/lucid_array/mixin.rb +163 -0
- data/lib/lucid_collection/base.rb +15 -0
- data/lib/lucid_collection/mixin.rb +241 -0
- data/lib/lucid_edge/base.rb +5 -0
- data/lib/lucid_edge/mixin.rb +243 -0
- data/lib/lucid_graph/base.rb +15 -0
- data/lib/lucid_graph/mixin.rb +672 -0
- data/lib/lucid_hash/base.rb +15 -0
- data/lib/lucid_hash/mixin.rb +169 -0
- data/lib/lucid_node/base.rb +5 -0
- data/lib/lucid_node/mixin.rb +201 -0
- metadata +180 -0
@@ -0,0 +1,163 @@
|
|
1
|
+
module LucidArray
|
2
|
+
module Mixin
|
3
|
+
def self.included(base)
|
4
|
+
if RUBY_ENGINE != 'opal'
|
5
|
+
Isomorfeus.add_valid_array_class(base) unless base == LucidArray::Base
|
6
|
+
end
|
7
|
+
|
8
|
+
base.extend(Isomorfeus::Data::PropDeclaration)
|
9
|
+
|
10
|
+
def to_gid
|
11
|
+
[@class_name, @props_json]
|
12
|
+
end
|
13
|
+
|
14
|
+
base.instance_exec do
|
15
|
+
def on_load_block
|
16
|
+
@on_load_block
|
17
|
+
end
|
18
|
+
|
19
|
+
def query_block
|
20
|
+
@query_block
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if RUBY_ENGINE == 'opal'
|
25
|
+
def initialize(store_path: nil, validated_props: nil)
|
26
|
+
@props = validated_props
|
27
|
+
@props_json = @props.to_json if @props
|
28
|
+
@class_name = self.class.name
|
29
|
+
@class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
|
30
|
+
@store_path = store_path ? store_path : [:data_state, :arrays, @class_name, @props_json]
|
31
|
+
end
|
32
|
+
|
33
|
+
def loaded?
|
34
|
+
Redux.fetch_by_path(*@store_path) ? true : false
|
35
|
+
end
|
36
|
+
|
37
|
+
def items
|
38
|
+
Redux.register_used_store_path(*@store_path)
|
39
|
+
raw_array = Redux.fetch_by_path(*@store_path)
|
40
|
+
raw_array ? raw_array : []
|
41
|
+
end
|
42
|
+
|
43
|
+
def method_missing(method_name, *args, &block)
|
44
|
+
Redux.register_used_store_path(*@store_path)
|
45
|
+
raw_array = Redux.fetch_by_path(*@store_path)
|
46
|
+
data_array = raw_array ? raw_array : []
|
47
|
+
data_array.send(method_name, *args, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_transport(inline: false)
|
51
|
+
Redux.register_used_store_path(*@store_path)
|
52
|
+
raw_array = Redux.fetch_by_path(*@store_path)
|
53
|
+
if inline
|
54
|
+
{ '_inline' => { @props_json => (raw_array ? raw_array : []) }}
|
55
|
+
else
|
56
|
+
{ 'arrays' => { @class_name => { @props_json => (raw_array ? raw_array : []) }}}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
base.instance_exec do
|
61
|
+
def load(props_hash = {})
|
62
|
+
validate_props(props_hash)
|
63
|
+
instance = self.new(validated_props: Isomorfeus::Data::Props.new(props_hash))
|
64
|
+
self.promise_load(props_hash, instance) unless instance.loaded?
|
65
|
+
instance
|
66
|
+
end
|
67
|
+
|
68
|
+
def on_load(&block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def promise_load(props_hash = {}, instance = nil)
|
72
|
+
unless instance
|
73
|
+
validate_props(props_hash)
|
74
|
+
instance = self.new(validated_props: Isomorfeus::Data::Props.new(props_hash))
|
75
|
+
end
|
76
|
+
|
77
|
+
props_json = instance.instance_variable_get(:@props_json)
|
78
|
+
|
79
|
+
Redux.register_used_store_path(:data_state, :arrays, self.name, props_json)
|
80
|
+
|
81
|
+
Isomorfeus::Transport.promise_send_path('Isomorfeus::Data::Handler::ArrayLoadHandler', self.name, props_json).then do |response|
|
82
|
+
if response[:agent_response].key?(:error)
|
83
|
+
`console.error(#{response[:agent_response][:error].to_n})`
|
84
|
+
raise response[:agent_response][:error]
|
85
|
+
end
|
86
|
+
Isomorfeus.store.dispatch(type: 'DATA_LOAD', data: response[:full_response][:data])
|
87
|
+
instance
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def query
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
else # RUBY_ENGINE
|
96
|
+
unless base == LucidArray::Base
|
97
|
+
base.prop :pub_sub_client, default: nil
|
98
|
+
base.prop :session_id, default: nil
|
99
|
+
base.prop :current_user, default: nil
|
100
|
+
end
|
101
|
+
|
102
|
+
def initialize(store_path: nil, validated_props: nil)
|
103
|
+
@props = validated_props
|
104
|
+
@props_json = @props.to_json if @props
|
105
|
+
@loaded = false
|
106
|
+
@class_name = self.class.name
|
107
|
+
@class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
|
108
|
+
end
|
109
|
+
|
110
|
+
def loaded?
|
111
|
+
@loaded
|
112
|
+
end
|
113
|
+
|
114
|
+
def [](name)
|
115
|
+
@data_array[name]
|
116
|
+
end
|
117
|
+
|
118
|
+
def items
|
119
|
+
@data_array
|
120
|
+
end
|
121
|
+
|
122
|
+
def method_missing(method_name, *args, &block)
|
123
|
+
@data_array.send(method_name, *args, &block)
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_transport(inline: false)
|
127
|
+
if inline
|
128
|
+
{ '_inline' => { @props_json => @data_array }}
|
129
|
+
else
|
130
|
+
{ 'arrays' => { @class_name => { @props_json => @data_array }}}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
base.instance_exec do
|
135
|
+
def load(props_hash = {})
|
136
|
+
validate_props(props_hash)
|
137
|
+
instance = self.new(validated_props: Isomorfeus::Data::Props.new(props_hash))
|
138
|
+
instance.instance_exec do
|
139
|
+
@data_array = self.class.query_block.call(props_hash)
|
140
|
+
@loaded = true
|
141
|
+
end
|
142
|
+
instance
|
143
|
+
end
|
144
|
+
|
145
|
+
def on_load(&block)
|
146
|
+
@on_load_block = block
|
147
|
+
end
|
148
|
+
|
149
|
+
def promise_load(props_hash = {}, instance = nil)
|
150
|
+
instance = self.load(props_hash)
|
151
|
+
result_promise = Promise.new
|
152
|
+
result_promise.resolve(instance)
|
153
|
+
result_promise
|
154
|
+
end
|
155
|
+
|
156
|
+
def query(&block)
|
157
|
+
@query_block = block
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end # RUBY_ENGINE
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module LucidCollection
|
2
|
+
class Base
|
3
|
+
include LucidCollection::Mixin
|
4
|
+
|
5
|
+
if RUBY_ENGINE != 'opal'
|
6
|
+
def self.inherited(base)
|
7
|
+
Isomorfeus.add_valid_collection_class(base)
|
8
|
+
|
9
|
+
base.prop :pub_sub_client, default: nil
|
10
|
+
base.prop :session_id, default: nil
|
11
|
+
base.prop :current_user, default: nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
module LucidCollection
|
2
|
+
module Mixin
|
3
|
+
def self.included(base)
|
4
|
+
if RUBY_ENGINE != 'opal'
|
5
|
+
Isomorfeus.add_valid_collection_class(base) unless base == LucidCollection::Base
|
6
|
+
end
|
7
|
+
|
8
|
+
base.extend(Isomorfeus::Data::PropDeclaration)
|
9
|
+
|
10
|
+
def find_node(attribute_hash = nil, &block)
|
11
|
+
if block_given?
|
12
|
+
nodes.each do |node|
|
13
|
+
return node if block.call(node)
|
14
|
+
end
|
15
|
+
else
|
16
|
+
node_class = attribute_hash.delete(:class)
|
17
|
+
is_a_module = attribute_hash.delete(:is_a)
|
18
|
+
nodes.each do |node|
|
19
|
+
if node_class
|
20
|
+
next unless node.class == node_class
|
21
|
+
end
|
22
|
+
if is_a_module
|
23
|
+
next unless node.is_a?(is_a_module)
|
24
|
+
end
|
25
|
+
found = true
|
26
|
+
attribute_hash.each do |k,v|
|
27
|
+
found &&= (node[k] == v)
|
28
|
+
break unless found
|
29
|
+
end
|
30
|
+
return node if found
|
31
|
+
end
|
32
|
+
end
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_nodes(attribute_hash = nil, &block)
|
37
|
+
found_nodes = Set.new
|
38
|
+
if block_given?
|
39
|
+
nodes.each do |node|
|
40
|
+
found_nodes << node if block.call(node)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
node_class = attribute_hash.delete(:class)
|
44
|
+
is_a_module = attribute_hash.delete(:is_a)
|
45
|
+
nodes.each do |node|
|
46
|
+
if node_class
|
47
|
+
next unless node.class == node_class
|
48
|
+
end
|
49
|
+
if is_a_module
|
50
|
+
next unless node.is_a?(is_a_module)
|
51
|
+
end
|
52
|
+
found = true
|
53
|
+
attribute_hash.each do |k,v|
|
54
|
+
found &&= (node[k] == v)
|
55
|
+
break unless found
|
56
|
+
end
|
57
|
+
found_nodes << node if found
|
58
|
+
end
|
59
|
+
end
|
60
|
+
found_nodes
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_gid
|
64
|
+
[@class_name, @props_json]
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_transport(inline: false)
|
68
|
+
if inline
|
69
|
+
{ '_inline' => { @props_json => nodes_as_cids }}
|
70
|
+
else
|
71
|
+
{ 'collections' => { @class_name => { @props_json => nodes_as_cids }}}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def included_items_to_transport
|
76
|
+
nodes_hash = {}
|
77
|
+
nodes.each do |node|
|
78
|
+
nodes_hash.deep_merge!(node.to_transport)
|
79
|
+
end
|
80
|
+
nodes_hash
|
81
|
+
end
|
82
|
+
|
83
|
+
base.instance_exec do
|
84
|
+
def on_load_block
|
85
|
+
@on_load_block
|
86
|
+
end
|
87
|
+
|
88
|
+
def query_block
|
89
|
+
@query_block
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if RUBY_ENGINE == 'opal'
|
94
|
+
def initialize(store_path: nil, validated_props: nil)
|
95
|
+
@props = validated_props
|
96
|
+
@props_json = @props.to_json if @props
|
97
|
+
@store_path = store_path
|
98
|
+
@class_name = self.class.name
|
99
|
+
@class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
|
100
|
+
@store_path = store_path ? store_path : [:data_state, :collections, @class_name, @props_json]
|
101
|
+
end
|
102
|
+
|
103
|
+
def loaded?
|
104
|
+
Redux.fetch_by_path(*@store_path) ? true : false
|
105
|
+
end
|
106
|
+
|
107
|
+
def find_node_by_id(node_id)
|
108
|
+
Redux.register_used_store_path(*@store_path)
|
109
|
+
nodes_as_cids.each do |node_cid|
|
110
|
+
return LucidNode::Base.node_from_cid(node_cid) if node_cid[1] == node_id
|
111
|
+
end
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
115
|
+
def nodes
|
116
|
+
# maybe use a node cache, maybe not:
|
117
|
+
# - pro node cache: maybe faster
|
118
|
+
# - contra node cache: js garbage collection fails because references are kept forever, memory usage just grows and grows
|
119
|
+
nodes_as_cids.map { |node_cid| LucidNode::Base.node_from_cid(node_cid) }
|
120
|
+
end
|
121
|
+
|
122
|
+
def nodes_as_cids
|
123
|
+
Redux.register_used_store_path(*@store_path)
|
124
|
+
node_cids = Redux.fetch_by_path(*@store_path)
|
125
|
+
node_cids ? node_cids : []
|
126
|
+
end
|
127
|
+
|
128
|
+
def method_missing(method_name, *args, &block)
|
129
|
+
if method_name.JS.startsWith('find_node_by_')
|
130
|
+
attribute = method_name[13..-1] # remove 'find_node_by_'
|
131
|
+
value = args[0]
|
132
|
+
attribute_hash = { attribute => value }
|
133
|
+
attribute_hash.merge!(args[1]) if args[1]
|
134
|
+
find_node(attribute_hash)
|
135
|
+
else
|
136
|
+
super
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
base.instance_exec do
|
141
|
+
def load(props_hash = {})
|
142
|
+
validate_props(props_hash)
|
143
|
+
instance = self.new(validated_props: Isomorfeus::Data::Props.new(props_hash))
|
144
|
+
self.promise_load(props_hash, instance) unless instance.loaded?
|
145
|
+
instance
|
146
|
+
end
|
147
|
+
|
148
|
+
def on_load(&block)
|
149
|
+
end
|
150
|
+
|
151
|
+
def promise_load(props_hash = {}, instance = nil)
|
152
|
+
unless instance
|
153
|
+
validate_props(props_hash)
|
154
|
+
instance = self.new(validated_props: Isomorfeus::Data::Props.new(props_hash))
|
155
|
+
end
|
156
|
+
|
157
|
+
props_json = instance.instance_variable_get(:@props_json)
|
158
|
+
|
159
|
+
Redux.register_used_store_path(:data_state, :collections, self.name, props_json)
|
160
|
+
|
161
|
+
Isomorfeus::Transport.promise_send_path('Isomorfeus::Data::Handler::CollectionLoadHandler', self.name, props_json).then do |response|
|
162
|
+
if response[:agent_response].key?(:error)
|
163
|
+
`console.error(#{response[:agent_response][:error].to_n})`
|
164
|
+
raise response[:agent_response][:error]
|
165
|
+
end
|
166
|
+
Isomorfeus.store.dispatch(type: 'DATA_LOAD', data: response[:full_response][:data])
|
167
|
+
instance
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def query
|
172
|
+
nil
|
173
|
+
end
|
174
|
+
end
|
175
|
+
else # RUBY_ENGINE
|
176
|
+
unless base == LucidCollection::Base
|
177
|
+
base.prop :pub_sub_client, default: nil
|
178
|
+
base.prop :session_id, default: nil
|
179
|
+
base.prop :current_user, default: nil
|
180
|
+
end
|
181
|
+
|
182
|
+
def initialize(store_path: nil, validated_props: nil)
|
183
|
+
@props = validated_props
|
184
|
+
@props_json = @props.to_json if @props
|
185
|
+
@loaded = false
|
186
|
+
@class_name = self.class.name
|
187
|
+
@class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
|
188
|
+
end
|
189
|
+
|
190
|
+
def loaded?
|
191
|
+
@loaded
|
192
|
+
end
|
193
|
+
|
194
|
+
def method_missing(method_name, *args, &block)
|
195
|
+
if method_name.start_with?('find_node_by_')
|
196
|
+
attribute = method_name[13..-1] # remove 'find_node_by_'
|
197
|
+
value = args[0]
|
198
|
+
attribute_hash = { attribute => value }
|
199
|
+
attribute_hash.merge!(args[1]) if args[1]
|
200
|
+
find_node(attribute_hash)
|
201
|
+
else
|
202
|
+
super
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def nodes_as_cids
|
207
|
+
nodes.map { |node| node.to_cid }
|
208
|
+
end
|
209
|
+
|
210
|
+
base.instance_exec do
|
211
|
+
attr_reader :nodes
|
212
|
+
|
213
|
+
def load(props_hash = {})
|
214
|
+
validate_props(props_hash)
|
215
|
+
instance = self.new(validated_props: Isomorfeus::Data::Props.new(props_hash))
|
216
|
+
instance.instance_exec do
|
217
|
+
@nodes = self.class.query_block.call(props_hash)
|
218
|
+
@loaded = true
|
219
|
+
end
|
220
|
+
instance
|
221
|
+
end
|
222
|
+
|
223
|
+
def on_load(&block)
|
224
|
+
@on_load_block = block
|
225
|
+
end
|
226
|
+
|
227
|
+
def promise_load(props_hash = {}, instance = nil)
|
228
|
+
instance = self.load(props_hash)
|
229
|
+
result_promise = Promise.new
|
230
|
+
result_promise.resolve(instance)
|
231
|
+
result_promise
|
232
|
+
end
|
233
|
+
|
234
|
+
def query(&block)
|
235
|
+
@query_block = block
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end # RUBY_ENGINE
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
module LucidEdge
|
2
|
+
module Mixin
|
3
|
+
def self.included(base)
|
4
|
+
attr_reader :id
|
5
|
+
|
6
|
+
def ==(other_node)
|
7
|
+
eql?(other_node)
|
8
|
+
end
|
9
|
+
|
10
|
+
def eql?(other_node)
|
11
|
+
@id == other_node.id && @class_name == other_node.instance_variable_get(:@class_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def id=(new_id)
|
15
|
+
new_id = new_id.to_s
|
16
|
+
changed_attributes[:id] = new_id
|
17
|
+
@id = new_id
|
18
|
+
end
|
19
|
+
|
20
|
+
def changed_attributes
|
21
|
+
@changed_attributes ||= Isomorfeus::Data::Props.new({})
|
22
|
+
end
|
23
|
+
|
24
|
+
def changed?
|
25
|
+
changed_attributes.any?
|
26
|
+
end
|
27
|
+
|
28
|
+
def to=(node)
|
29
|
+
@changed_to_cid = node.to_cid
|
30
|
+
node
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_cid
|
34
|
+
[@class_name, @id]
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid_attribute?(attr, value)
|
38
|
+
begin
|
39
|
+
validate_attribute!(attr, value)
|
40
|
+
true
|
41
|
+
rescue
|
42
|
+
false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate_attribute!(attr, value)
|
47
|
+
attr_options = self.class.attribute_options[attr]
|
48
|
+
|
49
|
+
if attr_options.key?(:class)
|
50
|
+
raise "#{attr}: value class is not #{attr_options[:class]}!" unless value.class == attr_options[:class]
|
51
|
+
end
|
52
|
+
|
53
|
+
if attr_options.key?(:is_a)
|
54
|
+
raise "#{attr}: value is not a #{attr_options[:class]}!" unless value.is_a?(attr_options[:is_a])
|
55
|
+
end
|
56
|
+
|
57
|
+
if attr_options.key?(:validate)
|
58
|
+
raise "#{attr}: value failed validation!" unless attr_options[:validate].call(value)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
base.instance_exec do
|
63
|
+
def attributes
|
64
|
+
attribute_options.keys
|
65
|
+
end
|
66
|
+
|
67
|
+
def attribute_options
|
68
|
+
@attribute_options ||= { id: {} }
|
69
|
+
end
|
70
|
+
|
71
|
+
def edge_from_cid(cid)
|
72
|
+
Isomorfeus.cached_edge_class(cid[0]).new({id: cid[1]})
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if RUBY_ENGINE == 'opal'
|
77
|
+
def initialize(attributes_hash = nil)
|
78
|
+
attributes_hash = {} unless attributes_hash
|
79
|
+
self.class.attributes.each do |attr|
|
80
|
+
next if attr == :to || attr == :from
|
81
|
+
if attributes_hash.key?(attr)
|
82
|
+
validate_attribute!(attr, attributes_hash[attr])
|
83
|
+
changed_attributes[attr] = attributes_hash[attr]
|
84
|
+
elsif self.class.attribute_options[attr].key?(:default)
|
85
|
+
changed_attributes[attr] = self.class.attribute_options[attr][:default]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
@id = attributes_hash[:id].to_s
|
89
|
+
@id = "new_#{object_id}" if @id.empty?
|
90
|
+
@changed_from_cid = attributes_hash[:from]&.to_cid
|
91
|
+
@changed_to_cid = attributes_hash[:to]&.to_cid
|
92
|
+
@class_name = self.class.name
|
93
|
+
@class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
|
94
|
+
end
|
95
|
+
|
96
|
+
def loaded?
|
97
|
+
Redux.fetch_by_path(:data_state, :edges, @class_name, @id) ? true : false
|
98
|
+
end
|
99
|
+
|
100
|
+
def from
|
101
|
+
cid = from_as_cid
|
102
|
+
cid ? LucidNode::Base.node_from_cid(cid) : nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def from_as_cid
|
106
|
+
Redux.register_used_store_path(:data_state, :edges, @class_name, @id, :from)
|
107
|
+
return @changed_from_cid if @changed_from_cid
|
108
|
+
cid = Redux.fetch_by_path(:data_state, :edges, @class_name, @id, :from)
|
109
|
+
cid ? cid : nil
|
110
|
+
end
|
111
|
+
|
112
|
+
def from=(node)
|
113
|
+
@changed_from_cid = node.to_cid
|
114
|
+
node
|
115
|
+
end
|
116
|
+
|
117
|
+
def to
|
118
|
+
cid = to_as_cid
|
119
|
+
cid ? LucidNode::Base.node_from_cid(cid) : nil
|
120
|
+
end
|
121
|
+
|
122
|
+
def to_as_cid
|
123
|
+
Redux.register_used_store_path(:data_state, :edges, @class_name, @id, :to)
|
124
|
+
return @changed_to_cid if @changed_to_cid
|
125
|
+
cid = Redux.fetch_by_path(:data_state, :edges, @class_name, @id, :to)
|
126
|
+
cid ? cid : nil
|
127
|
+
end
|
128
|
+
|
129
|
+
def to_transport(*args)
|
130
|
+
Redux.register_used_store_path(:data_state, :edges, @class_name, @id)
|
131
|
+
final_attributes = {}
|
132
|
+
self.class.attributes.each do |attr|
|
133
|
+
next if attr == :id
|
134
|
+
final_attributes[attr] = send(attr)
|
135
|
+
end
|
136
|
+
{ 'edges' => { @class_name => { @id => { from: from_as_cid, to: to_as_cid, attributes: final_attributes }}}}
|
137
|
+
end
|
138
|
+
|
139
|
+
base.instance_exec do
|
140
|
+
def attribute(name, options = {})
|
141
|
+
attribute_options[name] = options
|
142
|
+
|
143
|
+
define_method(name) do
|
144
|
+
Redux.register_used_store_path(:data_state, :edges, @class_name, @id, :attributes, name)
|
145
|
+
if changed_attributes.key?(name)
|
146
|
+
changed_attributes[name]
|
147
|
+
else
|
148
|
+
Redux.fetch_by_path(:data_state, :edges, @class_name, @id, :attributes, name)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
define_method("#{name}=") do |arg|
|
153
|
+
validate_attribute!(name, arg)
|
154
|
+
Redux.register_used_store_path(:data_state, :edges, @class_name, @id, :attributes, name)
|
155
|
+
changed_attributes.set(name, arg)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
else # RUBY_ENGINE
|
160
|
+
def initialize(attributes_hash = nil)
|
161
|
+
attributes_hash = {} unless attributes_hash
|
162
|
+
given_attributes = Isomorfeus::Data::Props.new(attributes_hash)
|
163
|
+
valid_attributes_hash = {}
|
164
|
+
self.class.attributes.each do |attr|
|
165
|
+
next if attr == :to || attr == :from
|
166
|
+
if given_attributes.key?(attr)
|
167
|
+
validate_attribute!(attr, given_attributes[attr])
|
168
|
+
valid_attributes_hash[attr] = given_attributes[attr]
|
169
|
+
elsif self.class.attribute_options[attr].key?(:default)
|
170
|
+
valid_attributes_hash[attr] = self.class.attribute_options[attr][:default]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
@attributes = Isomorfeus::Data::Props.new(valid_attributes_hash)
|
174
|
+
@id = @attributes[:id].to_s
|
175
|
+
@id = "new_#{object_id}" if @id.empty?
|
176
|
+
@from_cid = given_attributes[:from]&.to_cid
|
177
|
+
@changed_from_cid = nil
|
178
|
+
@to_cid = given_attributes[:to]&.to_cid
|
179
|
+
@changed_to_cid = nil
|
180
|
+
@class_name = self.class.name
|
181
|
+
@class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
|
182
|
+
end
|
183
|
+
|
184
|
+
def loaded?
|
185
|
+
true
|
186
|
+
end
|
187
|
+
|
188
|
+
def from
|
189
|
+
from_cid = from_as_cid
|
190
|
+
from_cid ? LucidNode::Base.node_from_cid(from_cid) : nil
|
191
|
+
end
|
192
|
+
|
193
|
+
def from_as_cid
|
194
|
+
@changed_from_cid ? @changed_from_cid : @from_cid
|
195
|
+
end
|
196
|
+
|
197
|
+
def from=(node)
|
198
|
+
@changed_from_cid = node.to_cid
|
199
|
+
node
|
200
|
+
end
|
201
|
+
|
202
|
+
def to
|
203
|
+
to_cid = to_as_cid
|
204
|
+
to_cid ? LucidNode::Base.node_from_cid(to_cid) : nil
|
205
|
+
end
|
206
|
+
|
207
|
+
def to_as_cid
|
208
|
+
@changed_to_cid ? @changed_to_cid : @to_cid
|
209
|
+
end
|
210
|
+
|
211
|
+
def to_transport(*args)
|
212
|
+
final_attributes = {}
|
213
|
+
self.class.attributes.each do |attr|
|
214
|
+
next if attr == :id
|
215
|
+
include_attribute = @attributes.key?(attr)
|
216
|
+
include_attribute = !self.class.attribute_options[attr][:server_only] if self.class.attribute_options[attr].key?(:server_only)
|
217
|
+
final_attributes[attr.to_s] = @attributes[attr] if include_attribute
|
218
|
+
end
|
219
|
+
{ 'edges' => { @class_name => { @id => { 'from' => from_as_cid, 'to' => to_as_cid, 'attributes' => final_attributes }}}}
|
220
|
+
end
|
221
|
+
|
222
|
+
base.instance_exec do
|
223
|
+
def attribute(name, options = {})
|
224
|
+
attribute_options[name] = options
|
225
|
+
|
226
|
+
define_method(name) do
|
227
|
+
if changed_attributes.key?(name)
|
228
|
+
changed_attributes[name]
|
229
|
+
else
|
230
|
+
@attributes[name]
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
define_method("#{name}=") do |arg|
|
235
|
+
validate_attribute!(name, arg)
|
236
|
+
changed_attributes.set(name, arg)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end # RUBY_ENGINE
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module LucidGraph
|
2
|
+
class Base
|
3
|
+
include LucidGraph::Mixin
|
4
|
+
|
5
|
+
if RUBY_ENGINE != 'opal'
|
6
|
+
def self.inherited(base)
|
7
|
+
Isomorfeus.add_valid_graph_class(base)
|
8
|
+
|
9
|
+
base.prop :pub_sub_client, default: nil
|
10
|
+
base.prop :session_id, default: nil
|
11
|
+
base.prop :current_user, default: nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|