isomorfeus-data 1.0.0.zeta10 → 1.0.0.zeta11

Sign up to get free protection for your applications and to get access to all the features.
@@ -18,53 +18,103 @@ module LucidData
18
18
  @node_collections ||= {}
19
19
  end
20
20
 
21
- def nodes(access_name, collection_class = nil)
22
- node_collections[access_name] = collection_class
21
+ def nodes(access_name, validate_hash = {})
22
+ node_collections[access_name] = validate_hash
23
23
 
24
24
  define_method(access_name) do
25
25
  node_collections[access_name]
26
26
  end
27
27
 
28
28
  define_method("#{access_name}=") do |collection|
29
+ _validate_node_collection(access_name, collection)
29
30
  @_changed = true
30
31
  node_collections[access_name] = collection
31
32
  node_collections[access_name].graph = self
32
33
  node_collections[access_name]
33
34
  end
34
35
 
35
- if collection_class
36
- singular_access_name = access_name.to_s.singularize
37
- define_singleton_method("valid_#{singular_access_name}?") do |node|
38
- collection_class.valid_node?(node)
39
- end
36
+ define_singleton_method("valid_#{access_name}?") do |collection|
37
+ _validate_node_collection(access_name, collection)
38
+ rescue
39
+ false
40
40
  end
41
41
  end
42
42
  alias documents nodes
43
43
  alias vertices nodes
44
44
  alias vertexes nodes
45
45
 
46
- def edges(access_name, collection_class = nil)
47
- edge_collections[access_name] = collection_class
46
+ def _validate_nodes(nodes_hash_or_array)
47
+ if nodes_hash_or_array.class == ::Hash
48
+ nodes_hash_or_array.each do |access_name, collection|
49
+ _validate_node_collection(access_name, collection)
50
+ end
51
+ else
52
+ _validate_node_collection(:nodes, nodes_hash_or_array)
53
+ end
54
+ end
55
+
56
+ def _validate_node_collection(access_name, collection)
57
+ unless node_collections.key?(access_name) || access_name == :nodes
58
+ raise "#{self.name}: No such node collection declared: '#{access_name}'!"
59
+ end
60
+ Isomorfeus::Data::ElementValidator.new(self.name, collection, node_collections[access_name]).validate! if node_collections[access_name]
61
+ end
62
+
63
+ def edges(access_name, validate_hash = {})
64
+ edge_collections[access_name] = validate_hash
48
65
 
49
66
  define_method(access_name) do
50
67
  edge_collections[access_name]
51
68
  end
52
69
 
53
70
  define_method("#{access_name}=") do |collection|
71
+ _validate_edge_collection(access_name, collection)
54
72
  @_changed = true
55
73
  edge_collections[access_name] = collection
56
74
  edge_collections[access_name].graph = self
57
75
  edge_collections[access_name]
58
76
  end
59
77
 
60
- if collection_class
61
- singular_access_name = access_name.to_s.singularize
62
- define_singleton_method("valid_#{singular_access_name}?") do |edge|
63
- collection_class.valid_edge?(edge)
64
- end
78
+ define_singleton_method("valid_#{access_name}?") do |collection|
79
+ _validate_edge_collection(access_name, collection)
80
+ rescue
81
+ false
65
82
  end
66
83
  end
67
84
  alias links edges
85
+
86
+ def _validate_edges(edges_hash_or_array)
87
+ if edges_hash_or_array.class == ::Hash
88
+ edges_hash_or_array.each do |access_name, collection|
89
+ _validate_edge_collection(access_name, collection)
90
+ end
91
+ else
92
+ _validate_edge_collection(:edges, edges_hash_or_array)
93
+ end
94
+ end
95
+
96
+ def _validate_edge_collection(access_name, collection)
97
+ unless edge_collections.key?(access_name) || access_name == :edges
98
+ raise "#{self.name}: No such edge collection declared: '#{access_name}'!"
99
+ end
100
+ Isomorfeus::Data::ElementValidator.new(self.name, collection, edge_collections[access_name]).validate! if edge_collections[access_name]
101
+ end
102
+ end
103
+
104
+ def _validate_edges(edges_hash_or_array)
105
+ self.class._validate_edges(edges_hash_or_array)
106
+ end
107
+
108
+ def _validate_edge_collection(access_name, collection)
109
+ self.class._validate_edge_collection(access_name, collection)
110
+ end
111
+
112
+ def _validate_nodes(nodes_hash_or_array)
113
+ self.class._validate_nodes(nodes_hash_or_array)
114
+ end
115
+
116
+ def _validate_node_collection(access_name, collection)
117
+ self.class._validate_node_collection(access_name, collection)
68
118
  end
69
119
 
70
120
  def method_missing(method_name, *args, &block)
@@ -200,7 +250,7 @@ module LucidData
200
250
  loaded = loaded?
201
251
 
202
252
  if attributes
203
- attributes.each { |a,v| _validate_attribute(a, v) }
253
+ _validate_attributes(attributes)
204
254
  if loaded
205
255
  raw_attributes = Redux.fetch_by_path(*@_store_path)
206
256
  if `raw_attributes === null`
@@ -219,6 +269,7 @@ module LucidData
219
269
  @_node_collections = {}
220
270
  nodes = nodes || documents || vertices || vertexes
221
271
  if nodes && loaded
272
+ _validate_nodes(nodes)
222
273
  if nodes.class == ::Hash
223
274
  self.class.node_collections.each_key do |access_name|
224
275
  if nodes.key?(access_name)
@@ -249,6 +300,7 @@ module LucidData
249
300
  @_edge_collections = {}
250
301
  edges = edges || links
251
302
  if edges && loaded
303
+ _validate_edges(edges)
252
304
  if edges.class == ::Hash
253
305
  self.class.edge_collections.each_key do |access_name|
254
306
  if edges.key?(access_name)
@@ -329,34 +381,54 @@ module LucidData
329
381
 
330
382
  base.instance_exec do
331
383
  def load(key:, pub_sub_client: nil, current_user: nil)
332
- data = instance_exec(key: key, &@_load_block)
333
- revision = nil
334
- revision = data.delete(:revision) if data.key?(:revision)
384
+ data = instance_exec(key: key, pub_sub_client: pub_sub_client, current_user: current_user, &@_load_block)
385
+ revision = data.delete(:revision)
335
386
  nodes = data.delete(:nodes)
336
387
  edges = data.delete(:edges)
337
388
  attributes = data.delete(:attributes)
338
389
  self.new(key: key, revision: revision, edges: edges, nodes: nodes, attributes: attributes)
339
390
  end
391
+
392
+ def save(key:, revision: nil, attributes: nil, edges: nil, links: nil, nodes: nil, documents: nil, vertices: nil, vertexes: nil,
393
+ pub_sub_client: nil, current_user: nil)
394
+ attributes = {} unless attributes
395
+ val_edges = edges || links
396
+ val_nodes = documents || nodes || vertexes || vertices
397
+ _validate_attributes(attributes) if attributes.any?
398
+ _validate_edges(val_edges)
399
+ _validate_nodes(val_nodes)
400
+ data = instance_exec(key: key, revision: revision, parts: parts, attributes: attributes,
401
+ pub_sub_client: pub_sub_client, current_user: current_user, &@_save_block)
402
+ revision = data.delete(:revision)
403
+ attributes = data.delete(:attributes)
404
+ documents = data.delete(:documents)
405
+ vertexes = data.delete(:vertexes)
406
+ vertices = data.delete(:vertices)
407
+ nodes = data.delete(:nodes)
408
+ edges = data.delete(:edges)
409
+ links = data.delete(:links)
410
+ self.new(key: key, revision: revision, attributes: attributes, edges: edges, links: links, nodes: nodes, documents: documents,
411
+ vertices: vertices, vertexes: vertexes, pub_sub_client: nil, current_user: nil)
412
+ end
340
413
  end
341
414
 
342
- def initialize(key:, revision: nil, attributes: nil, edges: nil, links: nil, nodes: nil, documents: nil, vertices: nil, vertexes: nil, composition: nil)
415
+ def initialize(key:, revision: nil, attributes: nil, edges: nil, links: nil, nodes: nil, documents: nil, vertices: nil, vertexes: nil,
416
+ composition: nil)
343
417
  @key = key.to_s
344
418
  @class_name = self.class.name
345
419
  @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
346
420
  @_revision = revision
347
421
  @_changed = false
348
422
  @_composition = composition
349
- @_validate_attributes = self.class.attribute_conditions.any?
350
423
  attributes = {} unless attributes
351
- if @_validate_attributes
352
- attributes.each { |a,v| _validate_attribute(a, v) }
353
- end
424
+ _validate_attributes(attributes) if attributes.any?
354
425
  @_raw_attributes = attributes
355
426
 
356
427
  # nodes
357
428
  @_node_collections = {}
358
429
  nodes = nodes || documents || vertices || vertexes
359
430
  if nodes.class == ::Hash
431
+ _validate_nodes(nodes)
360
432
  self.class.node_collections.each_key do |access_name|
361
433
  if nodes.key?(access_name)
362
434
  @_node_collections[access_name] = nodes[access_name]
@@ -364,6 +436,7 @@ module LucidData
364
436
  end
365
437
  end
366
438
  else
439
+ _validate_nodes(nodes) if nodes
367
440
  @_node_collections[:nodes] = nodes ? nodes : []
368
441
  @_node_collections[:nodes].graph = self if @_node_collections[:nodes].respond_to?(:graph=)
369
442
  end
@@ -372,6 +445,7 @@ module LucidData
372
445
  @_edge_collections = {}
373
446
  edges = edges || links
374
447
  if edges.class == ::Hash
448
+ _validate_edges(edges)
375
449
  self.class.edge_collections.each_key do |access_name|
376
450
  if edges.key?(access_name)
377
451
  @_edge_collections[access_name] = edges[access_name]
@@ -379,6 +453,7 @@ module LucidData
379
453
  end
380
454
  end
381
455
  else
456
+ _validate_edges(edges) if edges
382
457
  @_edge_collections[:edges] = edges ? edges : []
383
458
  @_edge_collections[:edges].graph = self if @_edge_collections[:edges].respond_to?(:graph=)
384
459
  end
@@ -4,6 +4,7 @@ module LucidData
4
4
  def self.included(base)
5
5
  base.include(Enumerable)
6
6
  base.extend(LucidPropDeclaration::Mixin)
7
+ base.include(Isomorfeus::Data::AttributeSupport)
7
8
  base.extend(Isomorfeus::Data::GenericClassApi)
8
9
  base.include(Isomorfeus::Data::GenericInstanceApi)
9
10
 
@@ -11,16 +12,25 @@ module LucidData
11
12
  attr_accessor :default_proc
12
13
 
13
14
  base.instance_exec do
14
- def attribute_conditions
15
- @attribute_conditions ||= {}
16
- end
17
-
18
15
  def valid_attribute?(attr_name, attr_value)
19
- return true unless @attribute_conditions
16
+ return true unless attribute_conditions.any?
20
17
  Isomorfeus::Props::Validator.new(self.name, attr_name, attr_value, attribute_conditions[attr_name]).validate!
21
18
  rescue
22
19
  false
23
20
  end
21
+
22
+ def _relaxed_validate_attribute(attr_name, attr_val)
23
+ Isomorfeus::Props::Validator.new(@class_name, attr_name, attr_val, attribute_conditions[attr_name]).validate!
24
+ end
25
+
26
+ def _relaxed_validate_attributes(attrs)
27
+ attribute_conditions.each_key do |attr|
28
+ if attribute_conditions[attr].key?(:required) && attribute_conditions[attr][:required] && !attrs.key?(attr)
29
+ raise "Required attribute #{attr} not given!"
30
+ end
31
+ end
32
+ attrs.each { |attr, val| _relaxed_validate_attribute(attr, val) } if attribute_conditions.any?
33
+ end
24
34
  end
25
35
 
26
36
  def composition
@@ -42,8 +52,12 @@ module LucidData
42
52
  { @class_name => { @key => hash }}
43
53
  end
44
54
 
45
- def _validate_attribute(attr_name, attr_val)
46
- Isomorfeus::Props::Validator.new(@class_name, attr_name, attr_val, self.class.attribute_conditions[attr_name]).validate!
55
+ def _relaxed_validate_attribute(attr_name, attr_val)
56
+ self.class._relaxed_validate_attribute(attr_name, attr_val)
57
+ end
58
+
59
+ def _relaxed_validate_attributes(attrs)
60
+ self.class._relaxed_validate_attributes(attrs)
47
61
  end
48
62
 
49
63
  if RUBY_ENGINE == 'opal'
@@ -63,7 +77,7 @@ module LucidData
63
77
  end
64
78
 
65
79
  define_method("#{name}=") do |val|
66
- _validate_attribute(name, val) if @_validate_attributes
80
+ _relaxed_validate_attribute(name, val) if @_validate_attributes
67
81
  @_changed_attributes[name] = val
68
82
  end
69
83
  end
@@ -82,9 +96,7 @@ module LucidData
82
96
  @_composition = composition
83
97
  @_validate_attributes = self.class.attribute_conditions.any?
84
98
  attributes = {} unless attributes
85
- if @_validate_attributes
86
- attributes.each { |a,v| _validate_attribute(a, v) }
87
- end
99
+ _relaxed_validate_attributes(attributes) if @_validate_attributes
88
100
  raw_attributes = Redux.fetch_by_path(*@_store_path)
89
101
  if `raw_attributes === null`
90
102
  @_changed_attributes = !attributes ? {} : attributes
@@ -129,7 +141,7 @@ module LucidData
129
141
  end
130
142
 
131
143
  def []=(name, val)
132
- _validate_attribute(name, val) if @_validate_attributes
144
+ _relaxed_validate_attribute(name, val) if @_validate_attributes
133
145
  changed!
134
146
  @_changed_attributes[name] = val
135
147
  end
@@ -161,7 +173,7 @@ module LucidData
161
173
  def method_missing(method_name, *args, &block)
162
174
  if method_name.end_with?('=')
163
175
  val = args[0]
164
- _validate_attribute(method_name, val) if @_validate_attributes
176
+ _relaxed_validate_attribute(method_name, val) if @_validate_attributes
165
177
  changed!
166
178
  @_changed_attributes[method_name] = val
167
179
  elsif args.size == 0 && hash.key?(method_name)
@@ -222,7 +234,7 @@ module LucidData
222
234
  end
223
235
 
224
236
  def store(name, val)
225
- _validate_attribute(name, val) if @_validate_attributes
237
+ _relaxed_validate_attribute(name, val) if @_validate_attributes
226
238
  @_changed_attributes[name] = val
227
239
  changed!
228
240
  val
@@ -265,16 +277,25 @@ module LucidData
265
277
  end
266
278
 
267
279
  define_method("#{name}=") do |val|
268
- _validate_attribute(name, val) if @_validate_attributes
280
+ _relaxed_validate_attribute(name, val) if @_validate_attributes
269
281
  changed!
270
282
  @_raw_attributes[name] = val
271
283
  end
272
284
  end
273
285
 
274
286
  def load(key:, pub_sub_client: nil, current_user: nil)
275
- data = instance_exec(key: key, &@_load_block)
276
- revision = nil
277
- revision = data.delete(:revision) if data.key?(:revision)
287
+ data = instance_exec(key: key, pub_sub_client: pub_sub_client, current_user: current_user, &@_load_block)
288
+ revision = data.delete(:revision)
289
+ attributes = data.delete(:attributes)
290
+ self.new(key: key, revision: revision, attributes: attributes)
291
+ end
292
+
293
+ def save(key:, revision: nil, attributes: nil, pub_sub_client: nil, current_user: nil)
294
+ attributes = {} unless attributes
295
+ _relaxed_validate_attributes(attributes)
296
+ data = instance_exec(key: key, revision: revision, attributes: attributes,
297
+ pub_sub_client: pub_sub_client, current_user: current_user, &@_save_block)
298
+ revision = data.delete(:revision)
278
299
  attributes = data.delete(:attributes)
279
300
  self.new(key: key, revision: revision, attributes: attributes)
280
301
  end
@@ -289,9 +310,7 @@ module LucidData
289
310
  @_changed = false
290
311
  @_validate_attributes = self.class.attribute_conditions.any?
291
312
  attributes = {} unless attributes
292
- if @_validate_attributes
293
- attributes.each { |a,v| _validate_attribute(a, v) }
294
- end
313
+ _relaxed_validate_attributes(attributes) if @_validate_attributes
295
314
  @_raw_attributes = attributes
296
315
  end
297
316
 
@@ -308,7 +327,7 @@ module LucidData
308
327
  end
309
328
 
310
329
  def []=(name, val)
311
- _validate_attribute(name, val) if @_validate_attributes
330
+ _relaxed_validate_attribute(name, val) if @_validate_attributes
312
331
  changed!
313
332
  @_raw_attributes[name] = val
314
333
  end
@@ -341,7 +360,7 @@ module LucidData
341
360
  def method_missing(method_name, *args, &block)
342
361
  if method_name.end_with?('=')
343
362
  val = args[0]
344
- _validate_attribute(name, val) if @_validate_attributes
363
+ _relaxed_validate_attribute(name, val) if @_validate_attributes
345
364
  changed!
346
365
  @_raw_attributes[name] = val
347
366
  elsif args.size == 0 && @_raw_attributes.key?(method_name)
@@ -379,7 +398,7 @@ module LucidData
379
398
  end
380
399
 
381
400
  def store(name, val)
382
- _validate_attribute(name, val) if @_validate_attributes
401
+ _relaxed_validate_attribute(name, val) if @_validate_attributes
383
402
  changed!
384
403
  @_raw_attributes[name] = val
385
404
  end
@@ -63,7 +63,7 @@ module LucidData
63
63
  @_changed = false
64
64
  loaded = loaded?
65
65
  if attributes
66
- attributes.each { |a,v| _validate_attribute(a, v) }
66
+ _validate_attributes(attributes)
67
67
  if loaded
68
68
  raw_attributes = Redux.fetch_by_path(*@_store_path)
69
69
  if `raw_attributes === null`
@@ -146,11 +146,19 @@ module LucidData
146
146
 
147
147
  base.instance_exec do
148
148
  def load(key:, pub_sub_client: nil, current_user: nil)
149
- data = instance_exec(key: key, &@_load_block)
150
- revision = nil
151
- revision = data.delete(:revision) if data.key?(:revision)
152
- data.delete(:_key)
153
- attributes = data.key?(:attributes) ? data.delete(:attributes) : data
149
+ data = instance_exec(key: key, pub_sub_client: pub_sub_client, current_user: current_user, &@_load_block)
150
+ revision = data.delete(:revision)
151
+ attributes = data.delete(:attributes)
152
+ self.new(key: key, revision: revision, attributes: attributes)
153
+ end
154
+
155
+ def save(key:, revision: nil, attributes: nil, pub_sub_client: nil, current_user: nil)
156
+ attributes = {} unless attributes
157
+ _validate_attributes(attributes)
158
+ data = instance_exec(key: key, revision: revision, attributes: attributes,
159
+ pub_sub_client: pub_sub_client, current_user: current_user, &@_save_block)
160
+ revision = data.delete(:revision)
161
+ attributes = data.delete(:attributes)
154
162
  self.new(key: key, revision: revision, attributes: attributes)
155
163
  end
156
164
  end
@@ -163,11 +171,8 @@ module LucidData
163
171
  @_collection = collection
164
172
  @_composition = composition
165
173
  @_changed = false
166
- @_validate_attributes = self.class.attribute_conditions.any?
167
174
  attributes = {} unless attributes
168
- if @_validate_attributes
169
- attributes.each { |a,v| _validate_attribute(a, v) }
170
- end
175
+ _validate_attributes(attributes) if attributes
171
176
  @_raw_attributes = attributes
172
177
  end
173
178
 
@@ -0,0 +1,93 @@
1
+ module LucidData
2
+ class QueryResult
3
+ attr_reader :key
4
+
5
+ def to_sid
6
+ [@class_name, @key]
7
+ end
8
+
9
+ if RUBY_ENGINE == 'opal'
10
+ def initialize(key: nil, result_set: {})
11
+ @class_name = 'LucidData::QueryResult'
12
+ @key = key ? key.to_s : self.object_id.to_s
13
+ @result_set = result_set
14
+ end
15
+
16
+ def _load_from_store!
17
+ @result_set = nil
18
+ end
19
+
20
+ def loaded?
21
+ Redux.fetch_by_path([:data_state, @class_name, @key]) ? true : false
22
+ end
23
+
24
+ def key?(k)
25
+ if @result_set.any?
26
+ @result_set.key?(k)
27
+ else
28
+ stored_results = Redux.fetch_by_path([:data_state, @class_name, @key])
29
+ `Object.hasOwnProperty(stored_results, k)`
30
+ end
31
+ end
32
+ alias has_key? key?
33
+
34
+ def result_set=(r)
35
+ @result_set = r
36
+ end
37
+
38
+ def method_missing(accessor_name, *args, &block)
39
+ raise "#{@class_name}: no such thing '#{accessor_name}‘in the results!" unless @result_set.key?(accessor_name)
40
+ sid = if @result_set.any?
41
+ @result_set[accessor_name]
42
+ else
43
+ stored_results = Redux.fetch_by_path([:data_state, @class_name, @key])
44
+ stored_results.JS[accessor_name]
45
+ end
46
+ Isomorfeus.instance_from_sid(sid)
47
+ end
48
+ else
49
+ def initialize(key: nil, result_set: {})
50
+ @class_name = 'LucidData::QueryResult'
51
+ @key = key ? key.to_s : self.object_id.to_s
52
+ @result_set = result_set
53
+ end
54
+
55
+ def loaded?
56
+ @result_set.any?
57
+ end
58
+
59
+ def key?(k)
60
+ @result_set.key?(k)
61
+ end
62
+ alias has_key? key?
63
+
64
+ def result_set=(r)
65
+ @result_set = r
66
+ end
67
+
68
+ def method_missing(accessor_name, *args, &block)
69
+ raise "#{@class_name}: no such thing '#{accessor_name}‘in the results!" unless @result_set.key?(accessor_name)
70
+ @result_set[accessor_name]
71
+ end
72
+
73
+ def to_transport
74
+ sids_hash = {}
75
+ @result_set.each do |key, value|
76
+ sids_hash[key] = value.to_sid
77
+ end
78
+ { @class_name => { @key => sids_hash }}
79
+ end
80
+
81
+ def included_items_to_transport
82
+ data_hash = {}
83
+ @result_set.each_value do |value|
84
+ data_hash.deep_merge!(value.to_transport)
85
+ if value.respond_to?(:included_items_to_transport)
86
+ data_hash.deep_merge!(value.included_items_to_transport)
87
+ end
88
+ end
89
+ data_hash
90
+ end
91
+ end
92
+ end
93
+ end