isomorfeus-data 2.5.5 → 22.9.0.rc1
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/lib/isomorfeus/data/config.rb +8 -25
- data/lib/isomorfeus/data/enhancer.rb +291 -0
- data/lib/isomorfeus/data/file_accelerator.rb +95 -0
- data/lib/isomorfeus/data/object_accelerator.rb +82 -90
- data/lib/isomorfeus/data/rack_middleware.rb +73 -0
- data/lib/isomorfeus/data/reducer.rb +47 -17
- data/lib/isomorfeus/data/sid.rb +34 -0
- data/lib/isomorfeus/data/version.rb +1 -1
- data/lib/isomorfeus-data.rb +27 -32
- data/lib/lucid_data_generic.rb +163 -0
- data/lib/lucid_file.rb +137 -0
- data/lib/lucid_object.rb +431 -0
- metadata +51 -47
- data/lib/data_uri/open_uri.rb +0 -22
- data/lib/data_uri/uri.rb +0 -61
- data/lib/data_uri.rb +0 -4
- data/lib/isomorfeus/data/field_support.rb +0 -269
- data/lib/isomorfeus/data/generic_class_api.rb +0 -127
- data/lib/isomorfeus/data/generic_instance_api.rb +0 -171
- data/lib/isomorfeus/data/handler/generic.rb +0 -133
- data/lib/isomorfeus_data/lucid_file/base.rb +0 -10
- data/lib/isomorfeus_data/lucid_file/mixin.rb +0 -281
- data/lib/isomorfeus_data/lucid_object/base.rb +0 -10
- data/lib/isomorfeus_data/lucid_object/mixin.rb +0 -250
- data/lib/isomorfeus_data/lucid_query/base.rb +0 -10
- data/lib/isomorfeus_data/lucid_query/mixin.rb +0 -112
- data/lib/isomorfeus_data/lucid_query_result.rb +0 -113
- data/opal/iso_uri.rb +0 -29
- data/opal/uri/common.rb +0 -18
- data/opal/uri/generic.rb +0 -47
data/lib/lucid_file.rb
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
class LucidFile < LucidDataGeneric
|
|
2
|
+
include LucidI18nMixin
|
|
3
|
+
|
|
4
|
+
VALID_METHODS = %i[key data data_uri content_type]
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
def api_path(key:)
|
|
8
|
+
"#{Isomorfeus.api_files_path}#{self.name}/#{key}"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def format_data_uri(c, d)
|
|
12
|
+
"data:#{c};base64,#{Base64.strict_encode64(d)}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def destroy(key:)
|
|
16
|
+
Isomorfeus.store.deferred_dispatch(type: 'FILE_DESTROY', class_name: self.name, key: key)
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def load!(key:, instance: nil)
|
|
21
|
+
instance = self.new(key: key, _loading: true) unless instance
|
|
22
|
+
Isomorfeus.something_loading!
|
|
23
|
+
Isomorfeus.store.deferred_dispatch(type: 'FILE_LOAD', class_name: self.name, key: key)
|
|
24
|
+
instance
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(key: nil, content_type: nil, data: nil, data_uri: nil, _loading: false)
|
|
29
|
+
super(key: key)
|
|
30
|
+
_update_paths
|
|
31
|
+
loaded = loaded?
|
|
32
|
+
@changed_uri_string = nil
|
|
33
|
+
if data_uri
|
|
34
|
+
@changed_uri_string = data_uri
|
|
35
|
+
elsif data || content_type
|
|
36
|
+
data = data.to_s unless data.is_a?(String)
|
|
37
|
+
if RUBY_ENGINE != 'opal'
|
|
38
|
+
content_type = Marcel::MimeType.for(data) unless content_type
|
|
39
|
+
end
|
|
40
|
+
@changed_uri_string = self.class.format_data_uri(content_type, data)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def create
|
|
45
|
+
raise 'Already created!' if revision > 0
|
|
46
|
+
@last_revision = 0
|
|
47
|
+
d = data_uri
|
|
48
|
+
unchange!
|
|
49
|
+
Isomorfeus.something_loading!
|
|
50
|
+
Isomorfeus.store.deferred_dispatch(type: "FILE_CREATE", class_name: @class_name, key: @key, data_uri: d, instance_uuid: instance_uuid, revision: 0)
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def save
|
|
55
|
+
@last_revision = revision
|
|
56
|
+
return create if @last_revision == 0
|
|
57
|
+
d = data_uri
|
|
58
|
+
unchange!
|
|
59
|
+
Isomorfeus.something_loading!
|
|
60
|
+
Isomorfeus.store.deferred_dispatch(type: "FILE_SAVE", class_name: @class_name, key: @key, data_uri: d, instance_uuid: instance_uuid, revision: @last_revision)
|
|
61
|
+
self
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def [](name)
|
|
65
|
+
self.send(name) if VALID_METHODS.include?(name)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def []=(name, value)
|
|
69
|
+
self.send("#{name}=".to_sym, value) if VALID_METHODS.include?(name)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def unchange!
|
|
73
|
+
super
|
|
74
|
+
@changed_uri_string = nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def _update_paths
|
|
78
|
+
@store_path = [:data_state, @class_name, @key, :data_uri]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def content_type
|
|
82
|
+
data_uri_object&.content_type
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def content_type=(c)
|
|
86
|
+
changed!
|
|
87
|
+
uri_string = @changed_uri_string ? @changed_uri_string : Isomorfeus.store.dig(*@store_path)
|
|
88
|
+
@changed_uri_string = self.class.format_data_uri(c, URI::Data.new(uri_string).data)
|
|
89
|
+
c
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def data_uri
|
|
93
|
+
@changed_uri_string ? @changed_uri_string : Isomorfeus.store.dig(*@store_path)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def data_uri=(d)
|
|
97
|
+
changed!
|
|
98
|
+
@changed_uri_string = d
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def data_uri_object
|
|
102
|
+
du = data_uri
|
|
103
|
+
URI::Data.new(du) if du
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def data
|
|
107
|
+
data_uri_object&.data
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def data=(d)
|
|
111
|
+
changed!
|
|
112
|
+
d = d.to_s unless d.is_a?(String)
|
|
113
|
+
if RUBY_ENGINE == 'opal'
|
|
114
|
+
ct = content_type
|
|
115
|
+
else
|
|
116
|
+
ct = Marcel::MimeType.for(d)
|
|
117
|
+
end
|
|
118
|
+
@changed_uri_string = self.class.format_data_uri(ct, d)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
if RUBY_ENGINE != 'opal'
|
|
122
|
+
class << self
|
|
123
|
+
def inherited(base)
|
|
124
|
+
Isomorfeus.add_valid_data_class(base) unless 'LucidFile' == base.name
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def file_accelerator
|
|
128
|
+
@file_accelerator ||= Isomorfeus::Data::FileAccelerator.new(self)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def exist?(key:)
|
|
132
|
+
raise "Not authorized!" unless current_user.authorized?(self, :load, key: key)
|
|
133
|
+
file_accelerator.exist?(sid: SID.new(self.name, key))
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end # RUBY_ENGINE
|
|
137
|
+
end
|
data/lib/lucid_object.rb
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
class LucidObject < LucidDataGeneric
|
|
2
|
+
include LucidI18nMixin
|
|
3
|
+
|
|
4
|
+
class SearchResultProxy
|
|
5
|
+
attr_reader :query_json
|
|
6
|
+
|
|
7
|
+
def initialize(class_name, query, params)
|
|
8
|
+
@store_path = [:data_state, :queries, class_name, query, JSON.dump(params)]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def method_missing(method, *args, &block)
|
|
12
|
+
all.send(method, *args, &block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def loaded?
|
|
16
|
+
!!as_sid_s
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def as_sid_s
|
|
20
|
+
Isomorfeus.store.dig(*@store_path)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def as_keys
|
|
24
|
+
a = as_sid_s
|
|
25
|
+
return [] unless a
|
|
26
|
+
a.map do |sid_s|
|
|
27
|
+
SID.from_s(sid_s).key
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def [](idx)
|
|
32
|
+
sid_s = as_sid_s&.fetch(idx)
|
|
33
|
+
LucidObject.instance_from_sid_s(sid_s) if sid_s
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def all
|
|
37
|
+
a = as_sid_s
|
|
38
|
+
return [] unless a
|
|
39
|
+
a.map do |sid_s|
|
|
40
|
+
LucidObject.instance_from_sid_s(sid_s)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def dig(*identifiers)
|
|
45
|
+
all.dig(*identifiers)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def length
|
|
49
|
+
as_sid_s&.size
|
|
50
|
+
end
|
|
51
|
+
alias size length
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
OBJECT_VALIDATION_PROC = proc do |v|
|
|
55
|
+
fail = false
|
|
56
|
+
if v.is_a?(SID)
|
|
57
|
+
# yes, a sid
|
|
58
|
+
elsif v.is_a?(Array)
|
|
59
|
+
v.each do |e|
|
|
60
|
+
fail = true unless (e.nil? || e.is_a?(LucidDataGeneric) || e.is_a?(SID) || (e.is_a?(String) && SID.is?(e)))
|
|
61
|
+
end
|
|
62
|
+
elsif v.is_a?(String)
|
|
63
|
+
fail = true unless SID.is?(v)
|
|
64
|
+
elsif !v.nil? && !v.is_a?(LucidObject)
|
|
65
|
+
fail = true
|
|
66
|
+
end
|
|
67
|
+
raise "must be nil, a LucidObject or a Array of LucidObjects, a SID or a Array of SIDs" if fail
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
ATTRIBUTE_VALIDATION_PROC = proc do |v|
|
|
71
|
+
fail = false
|
|
72
|
+
if v.is_a?(SID) || (v.is_a?(String) && SID.is?(v)) || v.is_a?(LucidDataGeneric)
|
|
73
|
+
fail = true
|
|
74
|
+
elsif v.is_a?(Array)
|
|
75
|
+
v.each do |e|
|
|
76
|
+
fail = true if e.is_a?(SID) || (e.is_a?(String) && SID.is?(e)) || e.is_a?(LucidDataGeneric)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
raise "LucidObjects or LucidFiles are not allowed as attributes!" if fail
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class << self
|
|
83
|
+
def search(query, params = nil)
|
|
84
|
+
proxy_instance = LucidObject::SearchResultProxy.new(self.name, query, params)
|
|
85
|
+
Isomorfeus.something_loading!
|
|
86
|
+
Isomorfeus.store.deferred_dispatch(type: 'DATA_SEARCH', class_name: self.name, query: query, params: params)
|
|
87
|
+
proxy_instance
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def load!(key:, instance: nil)
|
|
91
|
+
instance = self.new(key: key, _loading: true) unless instance
|
|
92
|
+
Isomorfeus.something_loading!
|
|
93
|
+
Isomorfeus.store.deferred_dispatch(type: 'DATA_LOAD', class_name: self.name, key: key)
|
|
94
|
+
instance
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def destroy(key:)
|
|
98
|
+
Isomorfeus.store.deferred_dispatch(type: 'DATA_DESTROY', class_name: self.name, key: key)
|
|
99
|
+
true
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def escape_string(s)
|
|
103
|
+
s.gsub(/([\\\&\:\(\)\[\]\{\}\!\"\~\^\|\<\>\=\*\?\+\-\s])/, '\\\\\1')
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def instance_from_sid_s(sid_s)
|
|
107
|
+
sid = SID.from_s(sid_s)
|
|
108
|
+
data_class = Isomorfeus.cached_data_class(sid.class_name)
|
|
109
|
+
data_class.load(key: sid.key)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def query(name, query_string, options = nil)
|
|
113
|
+
queries[name] = { query_string: query_string, options: options }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def queries
|
|
117
|
+
@queries ||= {}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def field_types
|
|
121
|
+
# determines how the item is stored in the index
|
|
122
|
+
@field_types ||= {}
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def field_options
|
|
126
|
+
# options for the index
|
|
127
|
+
@field_options ||= {}
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def field_conditions
|
|
131
|
+
# conditions for validating the field data
|
|
132
|
+
@field_conditions ||= {}
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def _register_field(name, type, options)
|
|
136
|
+
field_options[name] = {}
|
|
137
|
+
field_options[name][:default_boost] = options.delete(:default_boost) if options.key?(:default_boost)
|
|
138
|
+
field_options[name][:default_boost] = options.delete(:default_boost) if options.key?(:boost)
|
|
139
|
+
field_options[name][:index] = options.delete(:index) { :no }
|
|
140
|
+
field_options[name][:store] = options.delete(:store) { :yes }
|
|
141
|
+
field_options[name][:compress] = options.delete(:compress) if options.key?(:compress)
|
|
142
|
+
if field_options[name][:index] == :yes
|
|
143
|
+
field_options[name][:term_vector] = options.delete(:term_vector) { type == :text_field ? :with_positions_offsets : :no }
|
|
144
|
+
elsif field_options[name][:index] == :no
|
|
145
|
+
field_options[name][:term_vector] = :no
|
|
146
|
+
end
|
|
147
|
+
field_conditions[name] = options
|
|
148
|
+
field_types[name] = type
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def field(name, type, options)
|
|
152
|
+
_register_field(name, type, options)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def text_field(name, options = {})
|
|
156
|
+
default_options = { is_a: String, allow_nil: true, cast: true }
|
|
157
|
+
field(name, :text_field, default_options.merge(options))
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def attribute(name, options = {})
|
|
161
|
+
default_options = { validate_block: ATTRIBUTE_VALIDATION_PROC }
|
|
162
|
+
field(name, :attribute, default_options.merge(options))
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def object(name, options = {})
|
|
166
|
+
default_options = { validate_block: OBJECT_VALIDATION_PROC }
|
|
167
|
+
field(name, :object, default_options.merge(options))
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def validate_field!(field_name, val)
|
|
171
|
+
raise "no such field" unless field_options.key?(field_name)
|
|
172
|
+
Isomorfeus::Props::Validator.new(self.name, field_name, val, field_conditions[field_name]).validate!
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def valid_field?(field_name, val)
|
|
176
|
+
validate_field!(field_name, val)
|
|
177
|
+
rescue
|
|
178
|
+
false
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def valid_text_field?(field_name, val)
|
|
182
|
+
return valid_field?(field_name, val) if field_types[field_name] == :text_field
|
|
183
|
+
false
|
|
184
|
+
rescue
|
|
185
|
+
false
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def valid_attribute?(attr_name, val)
|
|
189
|
+
return valid_field?(attr_name, val) if field_types[attr_name] == :attribute
|
|
190
|
+
false
|
|
191
|
+
rescue
|
|
192
|
+
false
|
|
193
|
+
end
|
|
194
|
+
alias valid_embed? valid_attribute?
|
|
195
|
+
|
|
196
|
+
def valid_object?(obj_name, val)
|
|
197
|
+
return valid_field?(obj_name, val) if field_types[obj_name] == :object
|
|
198
|
+
false
|
|
199
|
+
rescue
|
|
200
|
+
false
|
|
201
|
+
end
|
|
202
|
+
alias valid_reference? valid_object?
|
|
203
|
+
|
|
204
|
+
def validate
|
|
205
|
+
Isomorfeus::Props::ValidateHashProxy.new
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def _validate_field(field_name, val)
|
|
209
|
+
Isomorfeus.raise_error(message: "#{self.name}: No such text_field, attribute or object declared: '#{field_name}'!") unless field_conditions.key?(field_name)
|
|
210
|
+
Isomorfeus::Props::Validator.new(self.name, field_name, val, field_conditions[field_name]).validated_value
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def _validate_fields(fields)
|
|
214
|
+
field_names = (fields.keys + field_conditions.keys).uniq
|
|
215
|
+
field_names.each do |field_name|
|
|
216
|
+
if field_conditions[field_name].key?(:required) && field_conditions[field_name][:required] && !fields.key?(field_name)
|
|
217
|
+
Isomorfeus.raise_error(message: "Required #{field_types[field_name]} #{field_name} not given!")
|
|
218
|
+
end
|
|
219
|
+
fields[field_name] = _validate_field(field_name, fields[field_name])
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def initialize(key: nil, fields: nil, attributes: nil, _loading: false)
|
|
225
|
+
super(key: key)
|
|
226
|
+
_update_paths
|
|
227
|
+
@objects = {}
|
|
228
|
+
@field_types = @self_class.field_types
|
|
229
|
+
loaded = loaded?
|
|
230
|
+
fields = attributes if attributes
|
|
231
|
+
if loaded
|
|
232
|
+
raw_fields = Isomorfeus.store.dig(*@store_path)
|
|
233
|
+
if raw_fields.nil?
|
|
234
|
+
if fields
|
|
235
|
+
_validate_fields(fields)
|
|
236
|
+
@changed_fields = fields
|
|
237
|
+
else
|
|
238
|
+
@changed_fields = {}
|
|
239
|
+
end
|
|
240
|
+
elsif raw_fields && fields && raw_fields != fields
|
|
241
|
+
_validate_fields(fields)
|
|
242
|
+
@changed_fields = fields
|
|
243
|
+
else
|
|
244
|
+
@changed_fields = {}
|
|
245
|
+
end
|
|
246
|
+
else
|
|
247
|
+
fields = {} unless fields
|
|
248
|
+
_validate_fields(fields) unless _loading
|
|
249
|
+
@changed_fields = fields
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def create
|
|
254
|
+
raise 'Already created!' if revision > 0
|
|
255
|
+
@last_revision = 0
|
|
256
|
+
f = _get_fields
|
|
257
|
+
unchange!
|
|
258
|
+
Isomorfeus.something_loading!
|
|
259
|
+
Isomorfeus.store.deferred_dispatch(type: "DATA_CREATE", class_name: @class_name, key: @key, fields: f, instance_uuid: instance_uuid, revision: 0)
|
|
260
|
+
self
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def save
|
|
264
|
+
@last_revision = revision
|
|
265
|
+
return create if @last_revision == 0
|
|
266
|
+
f = _get_fields
|
|
267
|
+
unchange!
|
|
268
|
+
Isomorfeus.something_loading!
|
|
269
|
+
Isomorfeus.store.deferred_dispatch(type: "DATA_SAVE", class_name: @class_name, key: @key, fields: f, instance_uuid: instance_uuid, revision: @last_revision)
|
|
270
|
+
self
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def _update_paths
|
|
274
|
+
@store_path = [:data_state, @class_name, @key, :fields]
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def _get_object(name)
|
|
278
|
+
return @changed_fields[name] if @changed_fields.key?(name)
|
|
279
|
+
return @objects[name] if @objects.key?(name)
|
|
280
|
+
sid_or_array = Isomorfeus.store.dig(*@store_path)&.fetch(name, nil)
|
|
281
|
+
return nil unless sid_or_array
|
|
282
|
+
if sid_or_array.is_a?(String)
|
|
283
|
+
@objects[name] = @self_class.instance_from_sid_s(sid_or_array)
|
|
284
|
+
elsif sid_or_array.is_a?(Array)
|
|
285
|
+
a = sid_or_array.map do |sid_s|
|
|
286
|
+
@self_class.instance_from_sid_s(sid_s)
|
|
287
|
+
end
|
|
288
|
+
a.compact!
|
|
289
|
+
@objects[name] = a
|
|
290
|
+
end
|
|
291
|
+
@objects[name]
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def _validate_field(field_name, val)
|
|
295
|
+
@self_class._validate_field(field_name, val)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def _validate_fields(fields)
|
|
299
|
+
@self_class._validate_fields(fields)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def [](name)
|
|
303
|
+
return key if name == :key
|
|
304
|
+
type = @field_types[name]
|
|
305
|
+
case type
|
|
306
|
+
when :text_field then _get_field(name) || ''
|
|
307
|
+
when :attribute then _get_field(name)
|
|
308
|
+
when :object then _get_object(name)
|
|
309
|
+
else
|
|
310
|
+
raise "No such field '#{name}' declared!"
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
alias_method :fetch, :[]
|
|
314
|
+
|
|
315
|
+
def []=(name, val)
|
|
316
|
+
return self.key = name if name == :key
|
|
317
|
+
val = _validate_field(name, val)
|
|
318
|
+
changed!
|
|
319
|
+
@changed_fields[name] = val
|
|
320
|
+
end
|
|
321
|
+
alias_method :store, :[]=
|
|
322
|
+
|
|
323
|
+
def dig(name, *more_names)
|
|
324
|
+
value = self[name]
|
|
325
|
+
if value.respond_to?(:dig)
|
|
326
|
+
value.dig(*more_names) rescue nil
|
|
327
|
+
else
|
|
328
|
+
value
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def fields
|
|
333
|
+
raw_fields = Isomorfeus.store.dig(*@store_path)
|
|
334
|
+
hash = raw_fields ? raw_fields.dup : {}
|
|
335
|
+
hash.merge!(@changed_fields) if @changed_fields
|
|
336
|
+
hash
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def _get_fields
|
|
340
|
+
sel_fields = fields.dup
|
|
341
|
+
@self_class.field_types.each do |field, type|
|
|
342
|
+
if type == :object
|
|
343
|
+
v = self[field]
|
|
344
|
+
sel_fields[field] = if v.is_a?(SID)
|
|
345
|
+
v.to_s
|
|
346
|
+
elsif v.is_a?(Array)
|
|
347
|
+
v.map do |o|
|
|
348
|
+
if o.is_a?(SID)
|
|
349
|
+
o.to_s
|
|
350
|
+
elsif o.is_a?(LucidObject)
|
|
351
|
+
o.sid.to_s
|
|
352
|
+
elsif o.is_a?(String)
|
|
353
|
+
o
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
elsif v.is_a?(LucidObject)
|
|
357
|
+
v.sid.to_s
|
|
358
|
+
elsif v.is_a?(String)
|
|
359
|
+
v
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
sel_fields
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def unchange!
|
|
367
|
+
@changed_fields = {}
|
|
368
|
+
super
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def each(&block)
|
|
372
|
+
fields.each(&block)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
if RUBY_ENGINE == 'opal'
|
|
376
|
+
def _get_field(name)
|
|
377
|
+
return @changed_fields[name] if @changed_fields.key?(name)
|
|
378
|
+
Isomorfeus.store.dig(*@store_path)&.fetch(name) { |n| @self_class.field_conditions[n][:default] }
|
|
379
|
+
end
|
|
380
|
+
else # RUBY_ENGINE
|
|
381
|
+
class << self
|
|
382
|
+
def inherited(base)
|
|
383
|
+
Isomorfeus.add_valid_data_class(base) unless %w[LucidObject LucidUser].include?(base.name)
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def exist?(key:)
|
|
387
|
+
raise "Not authorized!" unless current_user.authorized?(self, :load, key: key)
|
|
388
|
+
object_accelerator.exist?(sid_s: SID.new(self.name, key).to_s)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def exist_by_field?(field:, value:)
|
|
392
|
+
raise "Not authorized!" unless current_user.authorized?(self, :search, { query: :exist_by_field , params: { field: field, value: value }})
|
|
393
|
+
object_accelerator.exist_by_field?(field: field, value: value)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def field_by_key(key:, field:)
|
|
397
|
+
sid_s = SID.new(self.name, key).to_s
|
|
398
|
+
object_accelerator.field(sid_s: sid_s, field: field)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def object_accelerator
|
|
402
|
+
@object_accelerator ||= Isomorfeus::Data::ObjectAccelerator.new(self)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def each(&block)
|
|
406
|
+
if block_given?
|
|
407
|
+
object_accelerator.each do |sid_s|
|
|
408
|
+
sid = SID.from_s(sid_s)
|
|
409
|
+
block.call self.load(key: sid.key)
|
|
410
|
+
end
|
|
411
|
+
else
|
|
412
|
+
Enumerator.new do |yielder|
|
|
413
|
+
object_accelerator.each do |sid_s|
|
|
414
|
+
sid = SID.from_s(sid_s)
|
|
415
|
+
yielder << self.load(key: sid.key)
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
alias to_enum each
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def _get_field(name)
|
|
424
|
+
return @changed_fields[name] if @changed_fields.key?(name)
|
|
425
|
+
if @self_class.field_conditions[name][:server_only]
|
|
426
|
+
return @self_class.object_accelerator.field(sid_s: sid.to_s, field: name)
|
|
427
|
+
end
|
|
428
|
+
Isomorfeus.store.dig(*@store_path)&.fetch(name) { |n| @self_class.field_conditions[n][:default] }
|
|
429
|
+
end
|
|
430
|
+
end # RUBY_ENGINE
|
|
431
|
+
end
|