isomorfeus-data 1.0.0.zeta25 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +47 -21
  3. data/README.md +38 -46
  4. data/lib/isomorfeus/data/attribute_support.rb +176 -176
  5. data/lib/isomorfeus/data/config.rb +79 -110
  6. data/lib/isomorfeus/data/element_validator.rb +147 -147
  7. data/lib/isomorfeus/data/ferret_accelerator.rb +66 -0
  8. data/lib/isomorfeus/data/field_support.rb +110 -0
  9. data/lib/isomorfeus/data/generic_class_api.rb +136 -116
  10. data/lib/isomorfeus/data/generic_instance_api.rb +150 -145
  11. data/lib/isomorfeus/data/hamster_accelerator.rb +87 -0
  12. data/lib/isomorfeus/data/hamster_storage_expander.rb +94 -0
  13. data/lib/isomorfeus/data/handler/generic.rb +134 -138
  14. data/lib/isomorfeus/data/reducer.rb +30 -30
  15. data/lib/isomorfeus/data/version.rb +4 -4
  16. data/lib/isomorfeus-data.rb +56 -64
  17. data/lib/isomorfeus_data/lucid_document/base.rb +10 -0
  18. data/lib/isomorfeus_data/lucid_document/mixin.rb +148 -0
  19. data/lib/isomorfeus_data/lucid_file/base.rb +10 -0
  20. data/lib/isomorfeus_data/lucid_file/mixin.rb +217 -0
  21. data/lib/isomorfeus_data/lucid_object/base.rb +10 -0
  22. data/lib/isomorfeus_data/lucid_object/mixin.rb +216 -0
  23. data/lib/isomorfeus_data/lucid_query/base.rb +10 -0
  24. data/lib/isomorfeus_data/lucid_query/mixin.rb +81 -0
  25. data/lib/isomorfeus_data/lucid_query_result.rb +97 -0
  26. data/opal/uri/common.rb +18 -0
  27. data/opal/uri/generic.rb +47 -0
  28. data/opal/uri.rb +29 -0
  29. metadata +85 -96
  30. data/lib/isomorfeus/data/handler/arango.rb +0 -56
  31. data/lib/isomorfeus/data/handler/object_call.rb +0 -40
  32. data/lib/isomorfeus/data/handler/object_store.rb +0 -40
  33. data/lib/isomorfeus_data/lucid_data/array/base.rb +0 -13
  34. data/lib/isomorfeus_data/lucid_data/array/mixin.rb +0 -580
  35. data/lib/isomorfeus_data/lucid_data/collection/base.rb +0 -13
  36. data/lib/isomorfeus_data/lucid_data/collection/finders.rb +0 -83
  37. data/lib/isomorfeus_data/lucid_data/collection/mixin.rb +0 -737
  38. data/lib/isomorfeus_data/lucid_data/composition/base.rb +0 -13
  39. data/lib/isomorfeus_data/lucid_data/composition/mixin.rb +0 -234
  40. data/lib/isomorfeus_data/lucid_data/document/base.rb +0 -13
  41. data/lib/isomorfeus_data/lucid_data/document/mixin.rb +0 -9
  42. data/lib/isomorfeus_data/lucid_data/edge/base.rb +0 -13
  43. data/lib/isomorfeus_data/lucid_data/edge/mixin.rb +0 -286
  44. data/lib/isomorfeus_data/lucid_data/edge_collection/base.rb +0 -13
  45. data/lib/isomorfeus_data/lucid_data/edge_collection/finders.rb +0 -134
  46. data/lib/isomorfeus_data/lucid_data/edge_collection/mixin.rb +0 -747
  47. data/lib/isomorfeus_data/lucid_data/generic_collection.rb +0 -4
  48. data/lib/isomorfeus_data/lucid_data/generic_edge.rb +0 -4
  49. data/lib/isomorfeus_data/lucid_data/generic_edge_collection.rb +0 -4
  50. data/lib/isomorfeus_data/lucid_data/generic_node.rb +0 -4
  51. data/lib/isomorfeus_data/lucid_data/graph/base.rb +0 -13
  52. data/lib/isomorfeus_data/lucid_data/graph/finders.rb +0 -141
  53. data/lib/isomorfeus_data/lucid_data/graph/mixin.rb +0 -489
  54. data/lib/isomorfeus_data/lucid_data/hash/base.rb +0 -13
  55. data/lib/isomorfeus_data/lucid_data/hash/mixin.rb +0 -427
  56. data/lib/isomorfeus_data/lucid_data/link/base.rb +0 -13
  57. data/lib/isomorfeus_data/lucid_data/link/mixin.rb +0 -9
  58. data/lib/isomorfeus_data/lucid_data/link_collection/base.rb +0 -13
  59. data/lib/isomorfeus_data/lucid_data/link_collection/mixin.rb +0 -9
  60. data/lib/isomorfeus_data/lucid_data/node/base.rb +0 -13
  61. data/lib/isomorfeus_data/lucid_data/node/mixin.rb +0 -232
  62. data/lib/isomorfeus_data/lucid_data/query/base.rb +0 -13
  63. data/lib/isomorfeus_data/lucid_data/query/mixin.rb +0 -83
  64. data/lib/isomorfeus_data/lucid_data/query_result.rb +0 -95
  65. data/lib/isomorfeus_data/lucid_data/vertex/base.rb +0 -13
  66. data/lib/isomorfeus_data/lucid_data/vertex/mixin.rb +0 -9
  67. data/lib/lucid_arango/collection/base.rb +0 -13
  68. data/lib/lucid_arango/collection/mixin.rb +0 -18
  69. data/lib/lucid_arango/document/base.rb +0 -13
  70. data/lib/lucid_arango/document/mixin.rb +0 -9
  71. data/lib/lucid_arango/edge/base.rb +0 -13
  72. data/lib/lucid_arango/edge/mixin.rb +0 -18
  73. data/lib/lucid_arango/edge_collection/base.rb +0 -13
  74. data/lib/lucid_arango/edge_collection/mixin.rb +0 -18
  75. data/lib/lucid_arango/graph/base.rb +0 -13
  76. data/lib/lucid_arango/graph/mixin.rb +0 -18
  77. data/lib/lucid_arango/node/base.rb +0 -13
  78. data/lib/lucid_arango/node/mixin.rb +0 -79
  79. data/lib/lucid_arango/object/base.rb +0 -11
  80. data/lib/lucid_arango/object/mixin.rb +0 -158
  81. data/lib/lucid_arango/remote_object/base.rb +0 -11
  82. data/lib/lucid_arango/remote_object/mixin.rb +0 -17
  83. data/lib/lucid_arango/vertex/base.rb +0 -13
  84. data/lib/lucid_arango/vertex/mixin.rb +0 -9
@@ -0,0 +1,148 @@
1
+ module LucidDocument
2
+ module Mixin
3
+ def self.included(base)
4
+ base.include(Isomorfeus::Data::FieldSupport)
5
+ base.extend(Isomorfeus::Data::GenericClassApi)
6
+ base.include(Isomorfeus::Data::GenericInstanceApi)
7
+
8
+ def [](name)
9
+ send(name)
10
+ end
11
+
12
+ def []=(name, val)
13
+ send("#{name}=", val)
14
+ end
15
+
16
+ def changed!
17
+ @_changed = true
18
+ end
19
+
20
+ def to_transport
21
+ hash = { 'fields' => _get_selected_fields }
22
+ hash['revision'] = revision if revision
23
+ result = { @class_name => { @key => hash }}
24
+ result.deep_merge!(@class_name => { @previous_key => { new_key: @key}}) if @previous_key
25
+ result
26
+ end
27
+
28
+ if RUBY_ENGINE == 'opal'
29
+ def initialize(key: nil, revision: nil, fields: nil)
30
+ @key = key.nil? ? SecureRandom.uuid : key.to_s
31
+ @class_name = self.class.name
32
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
33
+ _update_paths
34
+ @_revision = revision ? revision : Redux.fetch_by_path(:data_state, :revision, @class_name, @key)
35
+ @_changed = false
36
+ loaded = loaded?
37
+ if fields
38
+ if loaded
39
+ raw_fields = Redux.fetch_by_path(*@_store_path)
40
+ if `raw_fields === null`
41
+ @_changed_fields = !fields ? {} : fields
42
+ elsif raw_fields && !fields.nil? && ::Hash.new(raw_fields) != fields
43
+ @_changed_fields = fields
44
+ end
45
+ else
46
+ @_changed_fields = fields
47
+ end
48
+ else
49
+ @_changed_fields = {}
50
+ end
51
+ end
52
+
53
+ def _load_from_store!
54
+ @_changed_fields = {}
55
+ @_changed = false
56
+ end
57
+
58
+ def _update_paths
59
+ @_store_path = [:data_state, @class_name, @key, :fields]
60
+ end
61
+
62
+ def each(&block)
63
+ fields.each(&block)
64
+ end
65
+ else # RUBY_ENGINE
66
+ Isomorfeus.add_valid_data_class(base) unless base == LucidDocument::Base
67
+
68
+ base.instance_exec do
69
+ def instance_from_transport(instance_data, _included_items_data)
70
+ key = instance_data[self.name].keys.first
71
+ revision = instance_data[self.name][key].key?('revision') ? instance_data[self.name][key]['revision'] : nil
72
+ fields = instance_data[self.name][key].key?('fields') ? instance_data[self.name][key]['fields'].transform_keys!(&:to_sym) : nil
73
+ new(key: key, revision: revision, fields: fields)
74
+ end
75
+
76
+ def setup_index(&block)
77
+ @_setup_index_block = block
78
+ end
79
+
80
+ def ferret_accelerator
81
+ return @ferret_accelerator if @ferret_accelerator
82
+ @ferret_accelerator = if @_setup_index_block
83
+ Isomorfeus::Data::FerretAccelerator.new(self, &@_setup_index_block)
84
+ else
85
+ Isomorfeus::Data::FerretAccelerator.new(self)
86
+ end
87
+ end
88
+
89
+ def search(query, options = {})
90
+ top_docs = []
91
+ self.ferret_accelerator.search_each(query, options) do |id|
92
+ doc = self.ferret_accelerator.load_doc(id)
93
+ top_docs << self.new(key: doc[:key], fields: doc) if doc
94
+ end
95
+ top_docs
96
+ end
97
+
98
+ execute_create do
99
+ doc = self.fields
100
+ doc[:key] = self.key.nil? ? SecureRandom.uuid : self.key
101
+ self.class.ferret_accelerator.create_doc(doc)
102
+ self
103
+ end
104
+
105
+ execute_destroy do |key:|
106
+ self.ferret_accelerator.destroy_doc(key)
107
+ end
108
+
109
+ execute_load do |key:|
110
+ doc = self.ferret_accelerator.load_doc(key)
111
+ doc.delete(:key)
112
+ self.new(key: key, fields: doc)
113
+ end
114
+
115
+ execute_save do
116
+ doc = self.fields
117
+ if self.key.nil?
118
+ doc[:key] = SecureRandom.uuid
119
+ self.class.ferret_accelerator.create_doc(doc)
120
+ else
121
+ doc[:key] = self.key
122
+ self.class.ferret_accelerator.save_doc(self.key, doc)
123
+ end
124
+ self
125
+ end
126
+ end
127
+
128
+ def initialize(key: nil, revision: nil, fields: nil)
129
+ @key = key.nil? ? SecureRandom.uuid : key.to_s
130
+ @class_name = self.class.name
131
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
132
+ @_revision = revision
133
+ @_changed = false
134
+ fields = {} unless fields
135
+ @_raw_fields = fields
136
+ end
137
+
138
+ def _unchange!
139
+ @_changed = false
140
+ end
141
+
142
+ def each(&block)
143
+ @_raw_fields.each(&block)
144
+ end
145
+ end # RUBY_ENGINE
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,10 @@
1
+ module LucidFile
2
+ class Base
3
+ def self.inherited(base)
4
+ base.include LucidFile::Mixin
5
+ if RUBY_ENGINE != 'opal'
6
+ Isomorfeus.add_valid_data_class(base)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,217 @@
1
+ module LucidFile
2
+ module Mixin
3
+ def self.included(base)
4
+ base.extend(Isomorfeus::Data::GenericClassApi)
5
+ base.include(Isomorfeus::Data::GenericInstanceApi)
6
+
7
+ def changed!
8
+ @_changed = true
9
+ end
10
+
11
+ def to_transport
12
+ hash = {}
13
+ hash['revision'] = revision if revision
14
+ hash['data_uri'] = data_uri
15
+ result = { @class_name => { @key => hash }}
16
+ result.deep_merge!(@class_name => { @previous_key => { new_key: @key }}) if @previous_key
17
+ result
18
+ end
19
+
20
+ def content_type
21
+ _reload
22
+ return @_data_uri_object.content_type if @_data_uri_object
23
+ nil
24
+ end
25
+
26
+ def content_type=(c)
27
+ changed!
28
+ _content_type(c)
29
+ end
30
+
31
+ def _content_type(c)
32
+ _reload
33
+ @_data_uri_string = _format_data_uri(c, @_data_uri_object.data)
34
+ @_data_uri_object = URI::Data.new(@_data_uri_string)
35
+ c
36
+ end
37
+
38
+ def data
39
+ _reload
40
+ @_data_uri_object.data
41
+ end
42
+
43
+ def data=(d)
44
+ changed!
45
+ _data(d)
46
+ end
47
+
48
+ def _data(d)
49
+ _reload
50
+ @_data_uri_string = _format_data_uri(self.content_type, d)
51
+ @_data_uri_object = URI::Data.new(@_data_uri_string)
52
+ d
53
+ end
54
+
55
+ def data_uri
56
+ _reload
57
+ @_data_uri_string
58
+ end
59
+
60
+ def data_uri=(d)
61
+ changed!
62
+ _data_uri(d)
63
+ end
64
+
65
+ def _data_uri(d)
66
+ _reload
67
+ if d.class == URI::Data
68
+ @_data_uri_string = _format_data_uri(d.content_type, d.data)
69
+ @_data_uri_object = d
70
+ else
71
+ @_data_uri_string = d
72
+ @_data_uri_object = URI::Data.new(d)
73
+ end
74
+ @_data_uri_string
75
+ end
76
+
77
+ def data_uri_object
78
+ _reload
79
+ @_data_uri_object
80
+ end
81
+
82
+ def _format_data_uri(c, d)
83
+ "data:#{c};base64,#{Base64.encode64(d).chop}"
84
+ end
85
+
86
+ if RUBY_ENGINE == 'opal'
87
+ base.instance_exec do
88
+ def files_path
89
+ end
90
+
91
+ def files_path=(_)
92
+ end
93
+ end
94
+
95
+ def initialize(key: nil, content_type: nil, data: nil, data_uri: nil, revision: nil)
96
+ @key = key.nil? ? SecureRandom.uuid : key.to_s
97
+ @class_name = self.class.name
98
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
99
+ _update_paths
100
+ @_revision = revision ? revision : Redux.fetch_by_path(:data_state, :revision, @class_name, @key)
101
+ @_changed = false
102
+ @_reload = false
103
+ loaded = loaded?
104
+ @_data_uri_object = nil
105
+ @_data_uri_string = nil
106
+ if data_uri
107
+ self.data_uri = data_uri
108
+ elsif data
109
+ self.data = data
110
+ self.content_type = content_type if content_type
111
+ else
112
+ self._data('')
113
+ self._content_type(content_type) if content_type
114
+ end
115
+ end
116
+
117
+ def _load_from_store!
118
+ @_changed = false
119
+ @_reload = true
120
+ end
121
+
122
+ def _reload
123
+ return unless @_reload
124
+ @_reload = false
125
+ d = Redux.fetch_by_path(*@_store_path)
126
+ self._data_uri(d) if d
127
+ end
128
+
129
+ def _update_paths
130
+ @_store_path = [:data_state, @class_name, @key, :data_uri]
131
+ end
132
+ else # RUBY_ENGINE
133
+ Isomorfeus.add_valid_file_class(base) unless base == LucidFile::Base
134
+
135
+ base.instance_exec do
136
+ def instance_from_transport(instance_data, _included_items_data)
137
+ key = instance_data[self.name].keys.first
138
+ revision = instance_data[self.name][key].key?('revision') ? instance_data[self.name][key]['revision'] : nil
139
+ data_uri = instance_data[self.name][key].key?('data_uri') ? instance_data[self.name][key]['data_uri'] : nil
140
+ new(key: key, revision: revision, data_uri: data_uri)
141
+ end
142
+
143
+ def files_path
144
+ @files_path ||= Isomorfeus.files_path
145
+ end
146
+
147
+ def files_path=(f)
148
+ @files_path = f
149
+ end
150
+
151
+ def check_and_prepare_path(key:)
152
+ Isomorfeus.raise_error(message: 'Invalid key (contains ".." or "\\")') if key.include?('..') || key.include?('\\')
153
+ elements = key.split('/')
154
+ Isomorfeus.raise_error(message: 'Invalid key (contains more than 2 slashes "/")') if elements.size > 3
155
+ file = elements.pop
156
+ if elements.size > 0
157
+ dir_path = ::File.expand_path(::File.join(files_path, *elements))
158
+ FileUtils.mkdir_p(path) unless Dir.exist?(dir_path)
159
+ ::File.join(dir_path, file)
160
+ else
161
+ FileUtils.mkdir_p(files_path) unless Dir.exist?(files_path)
162
+ ::File.join(files_path, file)
163
+ end
164
+ end
165
+
166
+ execute_create do
167
+ self.save
168
+ end
169
+
170
+ execute_destroy do |key:|
171
+ file = check_and_prepare_path(key: key)
172
+ ::FileUtils.rm_f(file)
173
+ true
174
+ end
175
+
176
+ execute_load do |key:|
177
+ file = check_and_prepare_path(key: key)
178
+ d = ::File.read(file)
179
+ instance = self.new(key: key)
180
+ instance.data = d
181
+ instance
182
+ end
183
+
184
+ execute_save do
185
+ file = self.class.check_and_prepare_path(key: self.key)
186
+ ::File.write(file, self.data)
187
+ self
188
+ end
189
+ end
190
+
191
+ def initialize(key: nil, content_type: nil, data: nil, data_uri: nil, revision: nil)
192
+ @key = key.nil? ? SecureRandom.uuid : key.to_s
193
+ @class_name = self.class.name
194
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
195
+ @_revision = revision
196
+ @_data_uri_object = nil
197
+ @_data_uri_string = nil
198
+ if data_uri
199
+ self._data_uri(data_uri)
200
+ else
201
+ self._data(data ? data : '')
202
+ self._content_type(content_type) if content_type
203
+ end
204
+ @_changed = false
205
+ end
206
+
207
+ def _reload
208
+ end
209
+
210
+ def _unchange!
211
+ @_data_uri = @_changed_data_uri if @_changed
212
+ @_changed = false
213
+ end
214
+ end # RUBY_ENGINE
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,10 @@
1
+ module LucidObject
2
+ class Base
3
+ def self.inherited(base)
4
+ base.include LucidObject::Mixin
5
+ if RUBY_ENGINE != 'opal'
6
+ Isomorfeus.add_valid_data_class(base)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,216 @@
1
+ module LucidObject
2
+ module Mixin
3
+ def self.included(base)
4
+ base.include(Isomorfeus::Data::AttributeSupport)
5
+ base.extend(Isomorfeus::Data::GenericClassApi)
6
+ base.include(Isomorfeus::Data::GenericInstanceApi)
7
+
8
+ def changed!
9
+ @_changed = true
10
+ end
11
+
12
+ def [](name)
13
+ send(name)
14
+ end
15
+
16
+ def []=(name, val)
17
+ send("#{name}=".to_sym, val)
18
+ end
19
+
20
+ def to_transport
21
+ hash = { 'attributes' => _get_selected_attributes }
22
+ hash['revision'] = revision if revision
23
+ result = { @class_name => { @key => hash }}
24
+ result.deep_merge!(@class_name => { @previous_key => { new_key: @key}}) if @previous_key
25
+ result
26
+ end
27
+
28
+ if RUBY_ENGINE == 'opal'
29
+ def initialize(key: nil, revision: nil, attributes: nil)
30
+ @key = key.nil? ? SecureRandom.uuid : key.to_s
31
+ @class_name = self.class.name
32
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
33
+ _update_paths
34
+ @_revision = revision ? revision : Redux.fetch_by_path(:data_state, :revision, @class_name, @key)
35
+ @_changed = false
36
+ loaded = loaded?
37
+ if attributes
38
+ _validate_attributes(attributes)
39
+ if loaded
40
+ raw_attributes = Redux.fetch_by_path(*@_store_path)
41
+ if `raw_attributes === null`
42
+ @_changed_attributes = !attributes ? {} : attributes
43
+ elsif raw_attributes && !attributes.nil? && ::Hash.new(raw_attributes) != attributes
44
+ @_changed_attributes = attributes
45
+ end
46
+ else
47
+ @_changed_attributes = attributes
48
+ end
49
+ else
50
+ @_changed_attributes = {}
51
+ end
52
+ end
53
+
54
+ def _load_from_store!
55
+ @_changed_attributes = {}
56
+ @_changed = false
57
+ end
58
+
59
+ def _update_paths
60
+ @_store_path = [:data_state, @class_name, @key, :attributes]
61
+ end
62
+
63
+ def each(&block)
64
+ attributes.each(&block)
65
+ end
66
+ else # RUBY_ENGINE
67
+ Isomorfeus.add_valid_data_class(base) unless base == LucidObject::Base
68
+
69
+ base.instance_exec do
70
+ def instance_from_transport(instance_data, _included_items_data)
71
+ key = instance_data[self.name].keys.first
72
+ revision = instance_data[self.name][key].key?('revision') ? instance_data[self.name][key]['revision'] : nil
73
+ attributes = instance_data[self.name][key].key?('attributes') ? instance_data[self.name][key]['attributes'].transform_keys!(&:to_sym) : nil
74
+ new(key: key, revision: revision, attributes: attributes)
75
+ end
76
+
77
+ def setup_environment(&block)
78
+ @_setup_environment_block = block
79
+ end
80
+
81
+ def setup_index(&block)
82
+ @_setup_index_block = block
83
+ end
84
+
85
+ def hamster_storage_expander
86
+ return @hamster_storage_expander if @hamster_storage_expander
87
+ @hamster_storage_expander = if @_setup_environment_block
88
+ Isomorfeus::Data::HamsterStorageExpander.new(&@_setup_index_block)
89
+ else
90
+ Isomorfeus::Data::HamsterStorageExpander.new
91
+ end
92
+ end
93
+
94
+ def hamster_accelerator
95
+ return @hamster_accelerator if @hamster_accelerator
96
+ @hamster_accelerator = if @_setup_index_block
97
+ Isomorfeus::Data::HamsterAccelerator.new(&@_setup_index_block)
98
+ else
99
+ Isomorfeus::Data::HamsterAccelerator.new
100
+ end
101
+ end
102
+
103
+ def search(attr, val, options = {})
104
+ idx_type = self.indexed_attributes[attr]
105
+ raise "Can only search indexed attributes, but attribute :#{attr} is not indexed!" unless idx_type
106
+ objs = []
107
+ if idx_type == :text
108
+ query = "+value:#{val} +class_name:#{self.name}"
109
+ query << " +attribute:#{attr}" if attr != '*'
110
+ self.hamster_accelerator.search_each(query, options) do |id|
111
+ doc = self.hamster_accelerator.load_doc(id)
112
+ if doc
113
+ sid_s = doc[:sid_s_attr].split(':|:')[0]
114
+ obj = self.load(key: sid_s)
115
+ objs << obj if obj
116
+ end
117
+ end
118
+ else
119
+ attr_s = ":[#{attr}]"
120
+ accept_all_attr = attr_s == ":[*]" ? true : false
121
+ self.hamster_storage_expander.search(":[:#{val}:]:") do |sid_s_attr|
122
+ if accept_all_attr || sid_s_attr.end_with?(attr_s)
123
+ sid_s = sid_s_attr.split(':|:[')[0]
124
+ obj = self.load(key: sid_s)
125
+ objs << obj if obj
126
+ end
127
+ end
128
+ end
129
+ objs
130
+ end
131
+
132
+ execute_create do
133
+ self.key = SecureRandom.uuid unless self.key
134
+ self.class.hamster_storage_expander.create_object(self.sid_s, self)
135
+ self.class.indexed_attributes.each do |attr, idx_type|
136
+ if idx_type == :text
137
+ self._store_text_indexed_attribute(attr)
138
+ else
139
+ self._store_value_indexed_attribute(attr)
140
+ end
141
+ end
142
+ self
143
+ end
144
+
145
+ execute_destroy do |key:|
146
+ key = key.to_s
147
+ sid_s = key.start_with?('[') ? key : gen_sid_s(key)
148
+ self.hamster_storage_expander.destroy_object(sid_s)
149
+ self.indexed_attributes.each do |attr, idx_type|
150
+ if idx_type == :text
151
+ self.hamster_accelerator.destroy_doc("#{sid_s}:|:[#{attr}]")
152
+ else
153
+ old_val = self.hamster_storage_expander.index_get("#{sid_s}:|:[#{attr}]")
154
+ self.hamster_storage_expander.index_delete("#{sid_s}:|:[#{attr}]", old_val)
155
+ self.hamster_storage_expander.index_delete(":[:#{old_val}:]:", "#{sid_s}:|:[#{attr}]")
156
+ end
157
+ end
158
+ true
159
+ end
160
+
161
+ execute_load do |key:|
162
+ key = key.to_s
163
+ sid_s = key.start_with?('[') ? key : gen_sid_s(key)
164
+ self.hamster_storage_expander.load_object(sid_s)
165
+ end
166
+
167
+ execute_save do
168
+ self.key = SecureRandom.uuid unless self.key
169
+ self.class.hamster_storage_expander.save_object(self.sid_s, self)
170
+ self.class.indexed_attributes.each do |attr, val|
171
+ if val == :text
172
+ self._store_text_indexed_attribute(attr)
173
+ else
174
+ self._store_value_indexed_attribute(attr)
175
+ end
176
+ end
177
+ self
178
+ end
179
+ end
180
+
181
+ def initialize(key: nil, revision: nil, attributes: nil)
182
+ @key = key.nil? ? SecureRandom.uuid : key.to_s
183
+ @class_name = self.class.name
184
+ @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
185
+ @_revision = revision
186
+ @_changed = false
187
+ attributes = {} unless attributes
188
+ _validate_attributes(attributes) if attributes
189
+ @_raw_attributes = attributes
190
+ end
191
+
192
+ def _store_text_indexed_attribute(attr)
193
+ doc = { sid_s_attr: "#{self.sid_s}:|:[#{attr}]", value: self.send(attr).to_s, attribute: attr.to_s, class_name: @class_name }
194
+ self.class.hamster_accelerator.save_doc("#{self.sid_s}:|:[#{attr}]", doc)
195
+ end
196
+
197
+ def _store_value_indexed_attribute(attr)
198
+ old_val = self.class.hamster_storage_expander.index_get("#{self.sid_s}:|:[#{attr}]")
199
+ self.class.hamster_storage_expander.index_delete("#{self.sid_s}:|:[#{attr}]", old_val)
200
+ self.class.hamster_storage_expander.index_delete(":[:#{old_val}:]:", "#{self.sid_s}:|:[#{attr}]")
201
+ val = "#{self.send(attr)}"[0..300]
202
+ self.class.hamster_storage_expander.index_put("#{self.sid_s}:|:[#{attr}]", val)
203
+ self.class.hamster_storage_expander.index_put(":[:#{val}:]:", "#{self.sid_s}:|:[#{attr}]")
204
+ end
205
+
206
+ def _unchange!
207
+ @_changed = false
208
+ end
209
+
210
+ def each(&block)
211
+ @_raw_attributes.each(&block)
212
+ end
213
+ end # RUBY_ENGINE
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,10 @@
1
+ module LucidQuery
2
+ class Base
3
+ def self.inherited(base)
4
+ base.include LucidQuery::Mixin
5
+ if RUBY_ENGINE != 'opal'
6
+ Isomorfeus.add_valid_data_class(base)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,81 @@
1
+ module LucidQuery
2
+ module Mixin
3
+ def self.included(base)
4
+ base.extend(LucidPropDeclaration::Mixin)
5
+
6
+ if RUBY_ENGINE == 'opal'
7
+ base.instance_exec do
8
+ def execute(**props)
9
+ props[:query_result_instance] = LucidQueryResult.new
10
+ promise_execute(props) unless props[:query_result_instance].loaded?
11
+ props[:query_result_instance]
12
+ end
13
+
14
+ def promise_execute(**props)
15
+ query_result_instance = props.delete(:query_result_instance)
16
+ query_result_instance = LucidQueryResult.new unless query_result_instance
17
+ props.each_key do |prop_name|
18
+ Isomorfeus.raise_error(message: "#{self.to_s} No such query prop declared: '#{prop_name}'!") unless declared_props.key?(prop_name)
19
+ end
20
+ props = validated_props(props)
21
+ props[:query_result_instance_key] = query_result_instance.key
22
+ Isomorfeus::Transport.promise_send_path( 'Isomorfeus::Data::Handler::Generic', self.name, :query, props).then do |agent|
23
+ if agent.processed
24
+ agent.result
25
+ else
26
+ agent.processed = true
27
+ if agent.response.key?(:error)
28
+ Isomorfeus.raise_error(message: agent.response[:error])
29
+ end
30
+ query_result_instance._load_from_store!
31
+ Isomorfeus.store.dispatch(type: 'DATA_LOAD', data: agent.full_response[:data])
32
+ agent.result = query_result_instance
33
+ end
34
+ end
35
+ end
36
+
37
+ def execute_query(_); end
38
+ end
39
+ else
40
+ unless base == LucidQuery::Base
41
+ Isomorfeus.add_valid_data_class(base)
42
+ end
43
+
44
+ base.instance_exec do
45
+ def promise_execute(**props)
46
+ instance = self.execute(**props)
47
+ result_promise = Promise.new
48
+ result_promise.resolve(instance)
49
+ result_promise
50
+ end
51
+
52
+ def execute(**props)
53
+ query_result_instance_key = props.delete(:query_result_instance_key)
54
+ query_result = LucidQueryResult.new(key: query_result_instance_key)
55
+ query_result.result_set = self.new(**props).instance_exec(&@_query_block)
56
+ query_result
57
+ end
58
+
59
+ def execute_query(&block)
60
+ @_query_block = block
61
+ end
62
+ end
63
+
64
+ attr_reader :props
65
+
66
+ def initialize(**props_hash)
67
+ props_hash = self.class.validated_props(props_hash)
68
+ @props = LucidProps.new(props_hash)
69
+ end
70
+
71
+ def current_user
72
+ Isomorfeus.current_user
73
+ end
74
+
75
+ def pub_sub_client
76
+ Isomorfeus.pub_sub_client
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end