isomorfeus-data 2.5.4 → 22.9.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,133 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Isomorfeus
4
- module Data
5
- module Handler
6
- class Generic < LucidHandler::Base
7
- # responsible for loading:
8
- # LucidObject
9
- # LucidFile
10
- # LucidQuery
11
-
12
- def process_request(response_agent)
13
- # promise_send_path('Isomorfeus::Data::Handler::Generic', self.to_s, action, props_hash)
14
- response_agent.request.each_key do |type_class_name|
15
- if Isomorfeus.valid_data_class_name?(type_class_name)
16
- type_class = Isomorfeus.cached_data_class(type_class_name)
17
- if type_class
18
- response_agent.request[type_class_name].each_key do |action|
19
- case action
20
- when 'load' then process_load(response_agent, type_class, type_class_name)
21
- when 'execute' then process_execute(response_agent, type_class, type_class_name)
22
- when 'create' then process_create(response_agent, type_class, type_class_name)
23
- when 'save' then process_save(response_agent, type_class, type_class_name)
24
- when 'destroy' then process_destroy(response_agent, type_class, type_class_name)
25
- else response_agent.error = { error: { action => 'No such thing!' }}
26
- end
27
- end
28
- else response_agent.error = { error: { type_class_name => 'No such class!' }}
29
- end
30
- else response_agent.error = { error: { type_class_name => 'Not a valid LucidData class!' }}
31
- end
32
- end
33
- rescue Exception => e
34
- response_agent.error = { error: "Isomorfeus::Data::Handler::Generic: #{e.message}\n#{e.backtrace.join("\n")}" }
35
- end
36
-
37
- def process_create(response_agent, type_class, type_class_name)
38
- # 'Isomorfeus::Data::Handler::Generic', self.name, :create, data_hash
39
- data = response_agent.request[type_class_name]['create']
40
- instance_data = data['instance']
41
- included_items_data = data.key?('included_items') ? data['included_items'] : nil
42
- if Isomorfeus.current_user.authorized?(type_class, :create, type_class.props_from_data(instance_data))
43
- instance = type_class.instance_from_transport(instance_data, included_items_data)
44
- created_type = instance.create
45
- if created_type
46
- response_agent.outer_result = {} unless response_agent.outer_result
47
- response_agent.outer_result.deep_merge!(data: created_type.to_transport)
48
- if created_type.respond_to?(:included_items_to_transport)
49
- response_agent.outer_result.deep_merge!(data: created_type.included_items_to_transport)
50
- end
51
- response_agent.agent_result = { success: 'ok' }
52
- else response_agent.error = { error: { type_class_name => 'Create returned nothing!' }}
53
- end
54
- else response_agent.error = { error: 'Access denied!' }
55
- end
56
- end
57
-
58
- def process_execute(response_agent, type_class, type_class_name)
59
- # 'Isomorfeus::Data::Handler::Generic', self.name, :execute, props_json
60
- props = response_agent.request[type_class_name]['execute']
61
- props.transform_keys!(&:to_sym)
62
- if Isomorfeus.current_user.authorized?(type_class, :execute, props)
63
- queried_type = type_class.execute(**props)
64
- if queried_type
65
- response_agent.outer_result = {} unless response_agent.outer_result
66
- response_agent.outer_result.deep_merge!(data: queried_type.to_transport)
67
- if queried_type.respond_to?(:included_items_to_transport)
68
- response_agent.outer_result.deep_merge!(data: queried_type.included_items_to_transport)
69
- end
70
- response_agent.agent_result = { success: 'ok' }
71
- else response_agent.error = { error: { type_class_name => 'Query returned nothing!' }}
72
- end
73
- else response_agent.error = { error: 'Access denied!' }
74
- end
75
- end
76
-
77
- def process_load(response_agent, type_class, type_class_name)
78
- # 'Isomorfeus::Data::Handler::Generic', self.name, :load, key: key
79
- props = response_agent.request[type_class_name]['load']
80
- props.transform_keys!(&:to_sym)
81
- if Isomorfeus.current_user.authorized?(type_class, :load, props)
82
- loaded_type = type_class.load(**props)
83
- if loaded_type
84
- response_agent.outer_result = {} unless response_agent.outer_result
85
- response_agent.outer_result.deep_merge!(data: loaded_type.to_transport)
86
- if loaded_type.respond_to?(:included_items_to_transport)
87
- response_agent.outer_result.deep_merge!(data: loaded_type.included_items_to_transport)
88
- end
89
- response_agent.agent_result = { success: 'ok' }
90
- else response_agent.error = { error: { type_class_name => 'Load returned nothing!' }}
91
- end
92
- else response_agent.error = { error: 'Access denied!' }
93
- end
94
- end
95
-
96
- def process_save(response_agent, type_class, type_class_name)
97
- # 'Isomorfeus::Data::Handler::Generic', self.name, :save, data_hash
98
- data = response_agent.request[type_class_name]['save']
99
- instance_data = data['instance']
100
- included_items_data = data.key?('included_items') ? data['included_items'] : nil
101
- if Isomorfeus.current_user.authorized?(type_class, :save, type_class.props_from_data(instance_data))
102
- instance = type_class.instance_from_transport(instance_data, included_items_data)
103
- saved_type = instance.save
104
- if saved_type
105
- response_agent.outer_result = {} unless response_agent.outer_result
106
- response_agent.outer_result.deep_merge!(data: saved_type.to_transport)
107
- if saved_type.respond_to?(:included_items_to_transport)
108
- response_agent.outer_result.deep_merge!(data: saved_type.included_items_to_transport)
109
- end
110
- response_agent.agent_result = { success: 'ok' }
111
- else response_agent.error = { error: { type_class_name => 'Save returned nothing!' }}
112
- end
113
- else response_agent.error = { error: 'Access denied!' }
114
- end
115
- end
116
-
117
- def process_destroy(response_agent, type_class, type_class_name)
118
- props = response_agent.request[type_class_name]['destroy']
119
- props.transform_keys!(&:to_sym)
120
- if Isomorfeus.current_user.authorized?(type_class, :destroy, props)
121
- result = type_class.destroy(**props)
122
- if result
123
- response_agent.agent_result = { success: 'ok' }
124
- else
125
- response_agent.error = { error: { type_class_name => 'Destroy failed!' }}
126
- end
127
- else response_agent.error = { error: 'Access denied!' }
128
- end
129
- end
130
- end
131
- end
132
- end
133
- end
@@ -1,10 +0,0 @@
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
@@ -1,281 +0,0 @@
1
- module LucidFile
2
- module Mixin
3
- def self.included(base)
4
- base.extend(Isomorfeus::Data::GenericClassApi)
5
- base.include(Isomorfeus::Data::GenericInstanceApi)
6
- base.include(LucidI18n::Mixin)
7
-
8
- def changed!
9
- @_changed = true
10
- end
11
-
12
- def to_transport
13
- hash = {}
14
- hash['revision'] = revision if revision
15
- hash['data_uri'] = data_uri
16
- result = { @class_name => { @key => hash }}
17
- result.deep_merge!(@class_name => { @previous_key => { new_key: @key }}) if @previous_key
18
- result
19
- end
20
-
21
- if RUBY_ENGINE == 'opal'
22
- base.instance_exec do
23
- def files_path
24
- end
25
-
26
- def files_path=(_)
27
- end
28
- end
29
-
30
- def initialize(key: nil, content_type: nil, data: nil, data_uri: nil, revision: nil, _loading: false)
31
- @key = key.nil? ? SecureRandom.uuid : key.to_s
32
- @class_name = self.class.name
33
- @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
34
- _update_paths
35
- @_revision = revision ? revision : Redux.fetch_by_path(:data_state, :revision, @class_name, @key)
36
- @_changed = false
37
- @_reload = false
38
- loaded = loaded?
39
- @_data_uri_object = nil
40
- @_data_uri_string = nil
41
- if data_uri
42
- self.data_uri = data_uri
43
- elsif data
44
- self.data = data
45
- self.content_type = content_type if content_type
46
- else
47
- self._data('')
48
- self._content_type(content_type) if content_type
49
- end
50
- end
51
-
52
- def _load_from_store!
53
- @_changed = false
54
- @_reload = true
55
- end
56
-
57
- def _reload
58
- return unless @_reload
59
- @_reload = false
60
- d = Redux.fetch_by_path(*@_store_path)
61
- self._data_uri(d) if d
62
- end
63
-
64
- def _update_paths
65
- @_store_path = [:data_state, @class_name, @key, :data_uri]
66
- end
67
-
68
- def content_type
69
- _reload
70
- return @_data_uri_object.content_type if @_data_uri_object
71
- nil
72
- end
73
-
74
- def content_type=(c)
75
- changed!
76
- _content_type(c)
77
- end
78
-
79
- def _content_type(c)
80
- _reload
81
- @_data_uri_string = _format_data_uri(c, @_data_uri_object.data)
82
- @_data_uri_object = URI::Data.new(@_data_uri_string)
83
- c
84
- end
85
-
86
- def data
87
- _reload
88
- @_data_uri_object.data
89
- end
90
-
91
- def data=(d)
92
- changed!
93
- _data(d)
94
- end
95
-
96
- def _data(d)
97
- _reload
98
- @_data_uri_string = _format_data_uri(self.content_type, d)
99
- @_data_uri_object = URI::Data.new(@_data_uri_string)
100
- d
101
- end
102
-
103
- def data_uri
104
- _reload
105
- @_data_uri_string
106
- end
107
-
108
- def data_uri=(d)
109
- changed!
110
- _data_uri(d)
111
- end
112
-
113
- def _data_uri(d)
114
- _reload
115
- if d.class == URI::Data
116
- @_data_uri_string = _format_data_uri(d.content_type, d.data)
117
- @_data_uri_object = d
118
- else
119
- @_data_uri_string = d
120
- @_data_uri_object = URI::Data.new(d)
121
- end
122
- @_data_uri_string
123
- end
124
-
125
- def data_uri_object
126
- _reload
127
- @_data_uri_object
128
- end
129
-
130
- def _format_data_uri(c, d)
131
- "data:#{c};base64,#{Base64.encode64(d).chop}"
132
- end
133
- else # RUBY_ENGINE
134
- Isomorfeus.add_valid_file_class(base) unless base == LucidFile::Base
135
-
136
- base.instance_exec do
137
- def instance_from_transport(instance_data, _included_items_data)
138
- key = instance_data[self.name].keys.first
139
- revision = instance_data[self.name][key].key?('revision') ? instance_data[self.name][key]['revision'] : nil
140
- data_uri = instance_data[self.name][key].key?('data_uri') ? instance_data[self.name][key]['data_uri'] : nil
141
- new(key: key, revision: revision, data_uri: data_uri)
142
- end
143
-
144
- def props_from_data(instance_data)
145
- key = instance_data[self.name].keys.first
146
- revision = instance_data[self.name][key].key?('revision') ? instance_data[self.name][key]['revision'] : nil
147
- data_uri = instance_data[self.name][key].key?('data_uri') ? instance_data[self.name][key]['data_uri'] : nil
148
- LucidProps.new({ key: key, revision: revision, data_uri: data_uri })
149
- end
150
-
151
- def files_path
152
- @files_path ||= Isomorfeus.files_path
153
- end
154
-
155
- def files_path=(f)
156
- @files_path = f
157
- end
158
-
159
- def check_and_prepare_path(key:)
160
- Isomorfeus.raise_error(message: 'Invalid key (contains ".." or "\\")') if key.include?('..') || key.include?('\\')
161
- elements = key.split('/')
162
- Isomorfeus.raise_error(message: 'Invalid key (contains more than 2 slashes "/")') if elements.size > 3
163
- file = elements.pop
164
- if elements.size > 0
165
- dir_path = ::File.expand_path(::File.join(files_path, *elements))
166
- FileUtils.mkdir_p(dir_path) unless Dir.exist?(dir_path)
167
- ::File.join(dir_path, file)
168
- else
169
- FileUtils.mkdir_p(files_path) unless Dir.exist?(files_path)
170
- ::File.join(files_path, file)
171
- end
172
- end
173
-
174
- execute_create do
175
- self.save
176
- end
177
-
178
- execute_destroy do |key:|
179
- file = check_and_prepare_path(key: key)
180
- ::FileUtils.rm_f(file)
181
- true
182
- end
183
-
184
- execute_load do |key:|
185
- file = check_and_prepare_path(key: key)
186
- if File.exist?(file)
187
- d = ::File.binread(file)
188
- instance = self.new(key: key, data: d)
189
- instance
190
- else
191
- nil
192
- end
193
- end
194
-
195
- execute_save do
196
- file = self.class.check_and_prepare_path(key: self.key)
197
- ::File.binwrite(file, self.data)
198
- self
199
- end
200
- end
201
-
202
- def initialize(key: nil, content_type: nil, data: nil, data_uri: nil, revision: nil)
203
- @key = key.nil? ? SecureRandom.uuid : key.to_s
204
- @class_name = self.class.name
205
- @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
206
- @_revision = revision
207
- if data_uri
208
- self._data_uri(data_uri)
209
- else
210
- @_data = data
211
- @_content_type = content_type
212
- end
213
- @_changed = false
214
- end
215
-
216
- def _unchange!
217
- @_changed = false
218
- end
219
-
220
- def content_type
221
- @_content_type = @_data_uri_object.content_type if !@_content_type && @_data_uri_object
222
- @_content_type
223
- end
224
-
225
- def content_type=(c)
226
- changed!
227
- _content_type(c)
228
- end
229
-
230
- def _content_type(c)
231
- if @_data_uri_string
232
- @_data_uri_string = _format_data_uri(c, @_data_uri_object.data)
233
- @_data_uri_object = URI::Data.new(@_data_uri_string)
234
- end
235
- @_content_type = c
236
- end
237
-
238
- def data
239
- @_data = @_data_uri_object.data if !@_data && @_data_uri_object
240
- @_data
241
- end
242
-
243
- def data=(d)
244
- changed!
245
- @_data = d
246
- end
247
-
248
- def data_uri
249
- _data_uri(_format_data_uri(content_type, @_data)) if !@_data_uri_string && @_data
250
- @_data_uri_string
251
- end
252
-
253
- def data_uri=(d)
254
- changed!
255
- _data_uri(d)
256
- end
257
-
258
- def _data_uri(d)
259
- if d.class == URI::Data
260
- d = '' if d.nil?
261
- @_data_uri_string = _format_data_uri(d.content_type, d.data)
262
- @_data_uri_object = d
263
- else
264
- @_data_uri_string = d
265
- @_data_uri_object = URI::Data.new(d)
266
- end
267
- @_data_uri_string
268
- end
269
-
270
- def data_uri_object
271
- _data_uri(@_data) if !@_data_uri_object && @_data
272
- @_data_uri_object
273
- end
274
-
275
- def _format_data_uri(c, d)
276
- "data:#{c};base64,#{Base64.encode64(d).chop}"
277
- end
278
- end # RUBY_ENGINE
279
- end
280
- end
281
- end
@@ -1,10 +0,0 @@
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
@@ -1,236 +0,0 @@
1
- module LucidObject
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
- base.include(LucidI18n::Mixin)
8
-
9
- base.instance_exec do
10
- def escape_string(s)
11
- s.gsub(/([\\\&\:\(\)\[\]\{\}\!\"\~\^\|\<\>\=\*\?\+\-\s])/, '\\\\\1')
12
- end
13
- end
14
-
15
- def [](name)
16
- send(name)
17
- end
18
-
19
- def []=(name, val)
20
- send("#{name}=".to_sym, val)
21
- end
22
-
23
- def changed!
24
- @_changed = true
25
- end
26
-
27
- def to_transport
28
- hash = { 'fields' => _get_selected_fields }
29
- hash['revision'] = revision if revision
30
- result = { @class_name => { @key => hash }}
31
- result.deep_merge!(@class_name => { @previous_key => { new_key: @key }}) if @previous_key
32
- result
33
- end
34
-
35
- def included_items_to_transport
36
- f = fields
37
- data_hash = {}
38
- self.class.field_types.each do |field, type|
39
- if type == :object
40
- v = f[field]
41
- if v
42
- data_hash.deep_merge!(v.to_transport)
43
- if v.respond_to?(:included_items_to_transport)
44
- data_hash.deep_merge!(v.included_items_to_transport)
45
- end
46
- end
47
- end
48
- end
49
- data_hash
50
- end
51
-
52
- if RUBY_ENGINE == 'opal'
53
- def initialize(key: nil, revision: nil, fields: nil, _loading: false, attributes: nil)
54
- @key = key.nil? ? SecureRandom.uuid : key.to_s
55
- @class_name = self.class.name
56
- @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
57
- _update_paths
58
- @_revision = revision ? revision : Redux.fetch_by_path(:data_state, :revision, @class_name, @key)
59
- @_objects = {}
60
- @_changed = false
61
- loaded = loaded?
62
- fields = attributes if attributes
63
- if loaded
64
- raw_fields = Redux.fetch_by_path(*@_store_path)
65
- if `raw_fields === null`
66
- if fields
67
- _validate_fields(fields)
68
- @_changed_fields = fields
69
- else
70
- @_changed_fields = {}
71
- end
72
- elsif raw_fields && fields && ::Hash.new(raw_fields) != fields
73
- _validate_fields(fields)
74
- @_changed_fields = fields
75
- else
76
- @_changed_fields = {}
77
- end
78
- else
79
- fields = {} unless fields
80
- _validate_fields(fields) unless _loading
81
- @_changed_fields = fields
82
- end
83
- end
84
-
85
- def _load_from_store!
86
- @_changed_fields = {}
87
- @_objects = {}
88
- @_changed = false
89
- end
90
-
91
- def _update_paths
92
- @_store_path = [:data_state, @class_name, @key, :fields]
93
- end
94
-
95
- def each(&block)
96
- fields.each(&block)
97
- end
98
- else # RUBY_ENGINE
99
- Isomorfeus.add_valid_data_class(base) unless base == LucidObject::Base
100
-
101
- base.instance_exec do
102
- def instance_from_transport(instance_data, included_items_data, _already_loaded = {})
103
- key = instance_data[self.name].keys.first
104
- ref_s = gen_ref_s(key)
105
- return _already_loaded[ref_s] if _already_loaded.key?(ref_s)
106
- revision = instance_data[self.name][key].key?('revision') ? instance_data[self.name][key]['revision'] : nil
107
- data_obj = new(key: key, revision: revision)
108
- _already_loaded[ref_s] = data_obj
109
- fields = instance_data[self.name][key].key?('fields') ? instance_data[self.name][key]['fields'].transform_keys(&:to_sym) : nil
110
- if fields
111
- field_types.each do |field, type|
112
- if type == :object
113
- sid = fields[field]
114
- if sid
115
- o_class_name = sid[0]
116
- raise "invalid data class #{type_class_name}" unless Isomorfeus.valid_data_class_name?(o_class_name)
117
- o_class = Isomorfeus.cached_data_class(o_class_name)
118
- o_data = { o_class_name => { sid[1] => included_items_data[o_class_name][sid[1]] }}
119
- if included_items_data && !included_items_data[self.name]&.key?(key)
120
- included_items_data.deep_merge!(instance_data)
121
- end
122
- fields[field] = o_class.instance_from_transport(o_data, included_items_data, _already_loaded)
123
- end
124
- end
125
- end
126
- end
127
- data_obj._validate_fields(fields)
128
- data_obj.fields.merge!(fields)
129
- data_obj
130
- end
131
-
132
- def props_from_data(instance_data)
133
- key = instance_data[self.name].keys.first
134
- revision = instance_data[self.name][key].key?('revision') ? instance_data[self.name][key]['revision'] : nil
135
- fields = instance_data[self.name][key].key?('fields') ? instance_data[self.name][key]['fields'].transform_keys!(&:to_sym) : nil
136
- LucidProps.new({ key: key, revision: revision }.merge!(fields))
137
- end
138
-
139
- def object_accelerator
140
- @object_accelerator ||= Isomorfeus::Data::ObjectAccelerator.new(self)
141
- end
142
-
143
- def each(&block)
144
- if block_given?
145
- self.object_accelerator.each do |fields|
146
- block.call self.new(key: fields.delete(:key), fields: fields)
147
- end
148
- else
149
- Enumerator.new do |yielder|
150
- self.object_accelerator.each do |fields|
151
- yielder << self.new(key: fields.delete(:key), fields: fields)
152
- end
153
- end
154
- end
155
- end
156
- alias to_enum each
157
-
158
- def search(field = nil, val = nil, options = {}, query: nil)
159
- if field && !self.field_options[field]&.fetch(:index) == :yes
160
- raise "Can only search indexed #{self.field_types{field}}s, but #{self.field_types{field}} :#{field} is not indexed!"
161
- end
162
- objs = []
163
- query = query ? query : "#{field}:#{val}"
164
- self.object_accelerator.search_each(query, options) do |id|
165
- fields = self.object_accelerator.load_object(id: id)
166
- objs << self.new(key: fields.delete(:key), fields: fields)
167
- end
168
- objs
169
- end
170
-
171
- execute_create do |_already_saved: {}|
172
- self.key = SecureRandom.uuid unless self.key
173
- unless _already_saved.key?(self.ref_s)
174
- _already_saved[self.ref_s] = self
175
- self.class.object_accelerator.create_object(self.key, fields, _already_saved)
176
- end
177
- self
178
- end
179
-
180
- execute_destroy do |key:|
181
- self.object_accelerator.destroy_object(key.to_s)
182
- true
183
- end
184
-
185
- execute_load do |key:, _already_loaded: {}|
186
- ref_s = self.gen_ref_s(@key)
187
- if _already_loaded.key?(ref_s)
188
- _already_loaded[ref_s]
189
- else
190
- _already_loaded[ref_s] = true
191
- fields = self.object_accelerator.load_object(key: key.to_s, already_loaded: _already_loaded)
192
- obj = fields ? self.new(key: fields.delete(:key), fields: fields) : nil
193
- _already_loaded[ref_s] = obj
194
- end
195
- end
196
-
197
- execute_save do |_already_saved: {}|
198
- self.key = SecureRandom.uuid unless self.key
199
- unless _already_saved.key?(self.ref_s)
200
- _already_saved[self.ref_s] = true
201
- self.class.object_accelerator.save_object(self.key, fields, _already_saved)
202
- end
203
- self
204
- end
205
- end
206
-
207
- def initialize(key: nil, revision: nil, fields: nil, attributes: nil)
208
- @key = key.nil? ? SecureRandom.uuid : key.to_s
209
- @class_name = self.class.name
210
- @class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
211
- @_revision = revision
212
- @_changed = false
213
- fields = attributes if attributes
214
- fields = {} unless fields
215
- _validate_fields(fields) if fields
216
- @_raw_fields = fields
217
- end
218
-
219
- def _unchange!
220
- @_changed = false
221
- end
222
-
223
- def each(&block)
224
- @_raw_fields.each(&block)
225
- end
226
-
227
- def reload
228
- new_instance = self.class.load(key: @key)
229
- @_raw_fields = new_instance.fields
230
- _unchange!
231
- self
232
- end
233
- end # RUBY_ENGINE
234
- end
235
- end
236
- end
@@ -1,10 +0,0 @@
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