rhodes-framework 1.1.1 → 1.2.0

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.
@@ -18,33 +18,7 @@
18
18
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
19
  #
20
20
  module Rhom
21
- module RhomObject
22
- # defines a method at runtime for the
23
- # dynamically created class
24
-
25
-
26
- # we override method_missing here so that instance variables,
27
- # when retrieved or set, are added to the object
28
- def method_missing(name, *args)
29
- unless name == Fixnum
30
- varname = name.to_s.gsub(/=/,"")
31
- setting = (name.to_s =~ /=/)
32
- inst_var = nil
33
-
34
- if setting
35
- inst_var = instance_variable_set( "@#{varname}", args[0] )
36
- else
37
- inst_var = instance_variable_get( "@#{varname}" )
38
- end
39
-
40
- inst_var
41
- end
42
- end
43
-
44
- def remove_var(name)
45
- remove_instance_variable("@#{name}")
46
- end
47
-
21
+ module RhomObject
48
22
  def strip_braces(str=nil)
49
23
  str ? str.gsub(/\{/,"").gsub(/\}/,"") : nil
50
24
  end
@@ -59,7 +33,7 @@ module Rhom
59
33
  end
60
34
 
61
35
  def extract_options(arr=[])
62
- arr.last.is_a?(::Hash) ? arr.pop : {}
36
+ arr.last.is_a?(Hash) ? arr.pop : {}
63
37
  end
64
38
 
65
39
  @@reserved_names = {"object" => "1",
@@ -73,9 +47,6 @@ module Rhom
73
47
 
74
48
  def method_name_reserved?(method)
75
49
  @@reserved_names.has_key?(method)
76
- end
77
- #def method_name_reserved?(method)
78
- # method =~ /\bobject\b|\bsource_id\b|\bupdate_type\b|\battrib_type\b|\btype\b|\bset_notification\b|\bclear_notification\b/
79
- #end
50
+ end
80
51
  end # RhomObject
81
52
  end # Rhom
@@ -26,148 +26,156 @@ module Rhom
26
26
  class RhomObjectFactory
27
27
 
28
28
  def initialize
29
- unless not defined? Rho::RhoConfig::sources
29
+ unless not defined? Rho::RhoConfig.sources
30
30
  init_objects
31
31
  end
32
32
  end
33
33
 
34
34
  # Initialize new object with dynamic attributes
35
35
  def init_objects
36
- Rho::RhoConfig::sources.each do |classname,source|
37
- unless Object::const_defined?(classname.intern)
38
- Object::const_set(classname.intern,
39
- Class::new do
36
+ Rho::RhoConfig.sources.each do |classname,source|
37
+ unless Object.const_defined?(classname.intern)
38
+ Object.const_set(classname.intern,
39
+ Class.new do
40
40
  include ::Rhom::RhomObject
41
41
  extend ::Rhom::RhomObject
42
+
43
+ # This holds the attributes for an instance of
44
+ # the rhom object
45
+ attr_accessor :vars
42
46
 
43
47
  def initialize(obj=nil)
44
- self.send("object=".to_sym(), "#{((Time.now.to_f - Time.mktime(2009,"jan",1,0,0,0,0).to_f) * 10**6).to_i}")
48
+ @vars = {}
49
+ self.vars['object'] = "#{((Time.now.to_f - Time.mktime(2009,"jan",1,0,0,0,0).to_f) * 10**6).to_i}"
45
50
  if obj
46
- self.send("source_id=".to_sym(), obj['source_id'].to_s)
47
- self.send("update_type=".to_sym(), 'create')
48
51
  obj.each do |key,value|
49
- val = self.inst_strip_braces(value)
50
- self.send("#{key}=".to_sym(), val)
52
+ self.vars[key] = value
53
+ end
54
+ end
55
+ end
56
+
57
+ def method_missing(name, *args)
58
+ unless name == Fixnum
59
+ varname = name.to_s.gsub(/\=/,"")
60
+ setting = (name.to_s =~ /=/)
61
+ if setting
62
+ @vars[varname] = args[0]
63
+ else
64
+ @vars[varname]
51
65
  end
52
66
  end
53
-
54
67
  end
55
68
 
56
69
  class << self
57
70
 
58
71
  def count
59
- ::Rhom::RhomDbAdapter::select_from_table(::Rhom::TABLE_NAME,
60
- 'object',
61
- {"source_id"=>get_source_id},
62
- {"distinct"=>true}).length
72
+ SyncEngine.lock_sync_mutex
73
+ res = ::Rhom::RhomDbAdapter.select_from_table('object_values','object', {"source_id"=>get_source_id}, {"distinct"=>true}).length
74
+ SyncEngine.unlock_sync_mutex
75
+ res
63
76
  end
64
77
 
65
78
  def get_source_id
66
- Rho::RhoConfig::sources[self.name.to_s]['source_id'].to_s
79
+ Rho::RhoConfig.sources[self.name.to_s]['source_id'].to_s
67
80
  end
68
81
 
69
82
  # retrieve a single record if object id provided, otherwise return
70
83
  # full list corresponding to factory's source id
71
84
  def find(*args)
72
- list = []
73
- hash_list = {}
85
+ raise ::Rhom::RecordNotFound if args[0].nil? or args.length == 0
86
+ puts "Inside find: args - #{args.inspect}"
87
+ ret_list = []
74
88
  conditions = {}
75
-
89
+ where_cond = nil
76
90
  # first find all query objects
77
91
  if args.first == :all
78
- conditions = {"source_id"=>get_source_id}
92
+ where_cond = {"source_id"=>get_source_id}
79
93
  elsif args.first.is_a?(String)
80
- conditions = {"object"=>strip_braces(args.first.to_s)}
94
+ where_cond = {"object"=>strip_braces(args.first.to_s)}
81
95
  end
82
-
96
+
83
97
  # do we have conditions?
84
98
  # if so, add them to the query
85
- condition_hash = {}
99
+ condition_hash = nil
86
100
  select_arr = nil
101
+ condition_str = nil
102
+ limit = nil
103
+ offset = nil
87
104
  if args[1]
88
- condition_hash = get_conditions_hash(args[1][:conditions]) if args[1] and args[1][:conditions] and args[1][:conditions].is_a?(Hash)
89
- conditions.merge!(condition_hash)
90
-
91
- select_arr = args[1][:select] if args[1][:select]
92
- end
93
-
94
- # process query, create, and update lists in order
95
- sql_attrs = 'object,attrib,value'
96
- ["query", "create", "update"].each do |update_type|
97
- conditions.merge!({"update_type"=>update_type})
98
- objs = ::Rhom::RhomDbAdapter::select_from_table(::Rhom::TABLE_NAME, sql_attrs, conditions, {"order by"=>'object'},select_arr)
99
-
100
- # fetch the rest of the attributes if we're searching by specific attrib value
101
- #if conditions and conditions.size > 0
102
- if args[1] and args[1][:conditions] and args[1][:conditions].is_a?(Hash)
103
- full_objects = []
104
- objs.each do |obj|
105
- if not select_arr
106
- full_objects += ::Rhom::RhomDbAdapter::select_from_table(::Rhom::TABLE_NAME, sql_attrs, {'object' => obj['object'].to_s})
107
- elsif select_arr and conditions
108
- full_objects += ::Rhom::RhomDbAdapter::select_from_table(::Rhom::TABLE_NAME, sql_attrs, {'object' => obj['object'].to_s}, nil, select_arr)
109
- end
105
+ if args[1][:conditions]
106
+ condition_hash = args[1][:conditions] if args[1][:conditions].is_a?(Hash)
107
+ # conditions are a string
108
+ condition_str = args[1][:conditions] if args[1][:conditions].is_a?(String)
109
+ # conditions are an array
110
+ if args[1][:conditions].is_a? (Array)
111
+ condition_str = args[1][:conditions][0].split(/\?/).each_with_index { |param,i|
112
+ param << args[1][:conditions][i+1].to_s
113
+ }.join(' ').to_s
110
114
  end
111
- objs = full_objects
112
115
  end
113
-
114
- # build up the object array where each
115
- # row in this array is a rhom_object
116
- #index = -1
117
- #hash_objects = {}
118
-
119
- objs.each do |obj|
120
- object = obj['object']
121
- attrib = obj['attrib']
122
- value = obj['value']
123
-
124
- #if not hash_objects[object]
125
- # list.push get_new_obj(obj)
126
- # index += 1
127
- # hash_objects[object] = index
128
- #elsif
129
- # index = hash_objects[object]
130
- #end
131
- #isReserved = method_name_reserved?(attrib)
132
- #This is required because update should override query
133
- #if not isReserved and list[index].send(attrib.to_sym)
134
- # list[index].remove_var(attrib)
135
- #end
136
- #list[index].send("#{attrib}=".to_sym(), value) if not isReserved
137
-
138
- isReserved = method_name_reserved?(attrib)
139
- hash_list[object] = get_new_obj(obj) if not hash_list[object]
140
- if not isReserved and hash_list[object].send(attrib.to_sym)
141
- hash_list[object].remove_var(attrib)
142
- end
143
- hash_list[object].send("#{attrib}=".to_sym(), value) if not isReserved
144
- #nil # remove the element from the array
116
+ if args[1][:per_page] and args[1][:offset]
117
+ limit = args[1][:per_page].to_s
118
+ offset = args[1][:offset].to_s
145
119
  end
146
-
120
+ select_arr = args[1][:select] if args[1][:select]
147
121
  end
148
- #hash_objects = nil
149
-
150
- # convert hash to array
151
- list = hash_list.values
152
- hash_list = nil
153
122
 
154
- # setup order by if provided
155
- order = extract_options(args)
156
- order_value = order[:order] if order and order[:order]
157
- if order_value
158
- order_sym = order_value.to_sym
159
- list.sort! {|x,y| x.send(order_sym) && y.send(order_sym) ? x.send(order_sym) <=> y.send(order_sym) : 0}
160
- end
123
+ start = Time.new
124
+ # return horizontal resultset from database
125
+ # for example, an object that has attributes name,industry:
126
+ # | object | name | industry |
127
+ # ---------------------------------------------------------------------------
128
+ # | 3560c0a0-ef58-2f40-68a5-48f39f63741b |A.G. Parr PLC 37862 |Entertainment|
129
+ attribs = get_attribs
130
+ if attribs and attribs.length > 0
131
+ sql = ""
132
+ sql << "SELECT * FROM (\n" if condition_hash or condition_str
133
+ sql << "SELECT object,\n"
134
+ attribs.reject! {|attrib| select_arr.index(attrib).nil?} if select_arr
135
+ start = Time.new
136
+ attribs.each do |attrib|
137
+ unless attrib.nil? or attrib.length == 0 or method_name_reserved?(attrib)
138
+ sql << "MAX(CASE WHEN attrib = '#{attrib}' AND update_type IN (#{::Rhom::UPDATE_TYPES.join(',')}) THEN value ELSE NULL END) AS \"#{attrib}\",\n"
139
+ end
140
+ end
141
+ sql.chomp!
142
+ sql.chop!
143
+ sql << " FROM object_values ov where update_type not in ('delete','update')\n"
144
+ sql << "AND " + ::Rhom::RhomDbAdapter.where_str(where_cond) + "\n" if where_cond and where_cond.length > 0
145
+ sql << "group by object\n"
146
+ sql << "order by \"#{args[1][:order]}\"" if args[1] and args[1][:order]
147
+ sql << ") WHERE " + ::Rhom::RhomDbAdapter.where_str(condition_hash) if condition_hash
148
+ sql << ") WHERE " + condition_str if condition_str
149
+ sql << " LIMIT " + limit + " OFFSET " + offset if limit and offset
161
150
 
162
- # return a single rhom object if searching for one
163
- if args.first == :first or args.first.is_a?(String)
164
- return list[0]
151
+ list = ::Rhom::RhomDbAdapter.execute_sql(sql)
152
+ puts "Database query took #{Time.new - start} sec, #{list.length} rows"
153
+ start = Time.new
154
+ list.each do |rowhash|
155
+ # always return object field with surrounding '{}'
156
+ rowhash['object'] = "{#{rowhash['object']}}"
157
+ new_obj = self.new
158
+ new_obj.vars.merge!(rowhash)
159
+ ret_list << new_obj
160
+ end
165
161
  end
166
- list
162
+ puts "Processing rhom objects took #{Time.new - start} sec, #{ret_list.length} objects"
163
+ args.first == :first || args.first.is_a?(String) ? ret_list[0] : ret_list
167
164
  end
168
165
 
169
- def find_all(args={})
170
- find(args)
166
+ # Alias for find
167
+ def find_all(args=nil)
168
+ find(:all, args)
169
+ end
170
+
171
+ # Returns a set of rhom objects, limiting the set to length :per_page
172
+ # If no :per_page is specified, the default size is 10
173
+ def paginate(args=nil)
174
+ # Default to 10 items per page
175
+ args[:page] ||= 0
176
+ args[:per_page] ||= 10
177
+ args[:offset] = args[:page] * args[:per_page]
178
+ find(:all, args)
171
179
  end
172
180
 
173
181
  def set_notification(url,params)
@@ -179,19 +187,12 @@ module Rhom
179
187
  end
180
188
 
181
189
  def ask(question)
182
- tmp_obj = get_new_obj(:object =>djb_hash("#{question}#{rand.to_s}", 10).to_s)
190
+ tmp_obj = self.new(:object =>djb_hash("#{question}#{rand.to_s}", 10).to_s)
183
191
  if question
184
192
  # We only support one ask at a time!
185
- ::Rhom::RhomDbAdapter::delete_from_table(::Rhom::TABLE_NAME,
186
- {"source_id"=>get_source_id,
187
- "update_type"=>'ask'})
188
- ::Rhom::RhomDbAdapter::insert_into_table(::Rhom::TABLE_NAME,
189
- {"source_id"=>get_source_id,
190
- "object"=>tmp_obj.object,
191
- "attrib"=>'question',
192
- "value"=>Rho::RhoSupport.url_encode(question),
193
- "update_type"=>'ask'})
194
- SyncEngine::dosync
193
+ ::Rhom::RhomDbAdapter.delete_from_table('object_values', {"source_id"=>get_source_id, "update_type"=>'ask'})
194
+ ::Rhom::RhomDbAdapter.insert_into_table('object_values', {"source_id"=>get_source_id, "object"=>tmp_obj.object, "attrib"=>'question', "value"=>Rho::RhoSupport.url_encode(question), "update_type"=>'ask'})
195
+ SyncEngine.dosync
195
196
  end
196
197
  end
197
198
 
@@ -200,24 +201,24 @@ module Rhom
200
201
  if conditions
201
202
  del_conditions = get_conditions_hash(conditions[:conditions])
202
203
  # find all relevant objects, then delete them
203
- del_objects = ::Rhom::RhomDbAdapter::select_from_table(::Rhom::TABLE_NAME,
204
- 'object',
205
- del_conditions.merge!({"source_id"=>get_source_id}),
206
- {"distinct"=>true})
204
+ del_objects = ::Rhom::RhomDbAdapter.select_from_table('object_values', 'object', del_conditions.merge!({"source_id"=>get_source_id}), {"distinct"=>true})
207
205
  del_objects.each do |obj|
208
- ::Rhom::RhomDbAdapter::delete_from_table(::Rhom::TABLE_NAME, {'object'=>obj['object']})
206
+ ::Rhom::RhomDbAdapter.delete_from_table('object_values', {'object'=>obj['object']})
209
207
  end
210
208
  else
211
- ::Rhom::RhomDbAdapter::delete_from_table(::Rhom::TABLE_NAME, {"source_id"=>get_source_id})
209
+ ::Rhom::RhomDbAdapter.delete_from_table('object_values', {"source_id"=>get_source_id})
212
210
  end
213
211
  end
214
212
 
215
213
  private
216
- # returns new model instance with a temp object id
217
- def get_new_obj(obj)
218
- tmp_obj = self.new
219
- tmp_obj.send("object=".to_sym(), "{#{obj['object'].to_s}}")
220
- tmp_obj
214
+
215
+ # returns attributes for the source
216
+ def get_attribs
217
+ attribs = ::Rhom::RhomDbAdapter.select_from_table('object_values','attrib', {"source_id"=>get_source_id}, {"distinct"=>true})
218
+ attribs.collect! do |attrib|
219
+ attrib['attrib']
220
+ end
221
+ attribs
221
222
  end
222
223
 
223
224
  # get hash of conditions in sql form
@@ -242,14 +243,10 @@ module Rhom
242
243
  update_type=self.get_update_type_by_source('delete')
243
244
  if obj
244
245
  # first delete the record from viewable list
245
- result = ::Rhom::RhomDbAdapter::delete_from_table(::Rhom::TABLE_NAME,
246
- {"object"=>obj})
246
+ result = ::Rhom::RhomDbAdapter.delete_from_table('object_values', {"object"=>obj})
247
247
  if update_type
248
248
  # now add delete operation
249
- result = ::Rhom::RhomDbAdapter::insert_into_table(::Rhom::TABLE_NAME,
250
- {"source_id"=>self.get_inst_source_id,
251
- "object"=>obj,
252
- "update_type"=>update_type})
249
+ result = ::Rhom::RhomDbAdapter.insert_into_table('object_values', {"source_id"=>self.get_inst_source_id, "object"=>obj, "update_type"=>update_type})
253
250
  end
254
251
  end
255
252
  result
@@ -261,21 +258,29 @@ module Rhom
261
258
  # iterate over each instance variable and insert create row to table
262
259
  obj = self.inst_strip_braces(self.object)
263
260
  update_type=self.get_update_type_by_source('create')
264
- self.instance_variables.each do |method|
265
- method = method.to_s.gsub(/@/,"")
266
- # Don't save objects with braces to database
267
- val = self.inst_strip_braces(self.send(method.to_sym))
268
- # add rows excluding object, source_id and update_type
269
- unless self.method_name_reserved?(method)
270
- fields = {"source_id"=>self.get_inst_source_id,
271
- "object"=>obj,
272
- "attrib"=>method,
273
- "value"=>val,
274
- "update_type"=>update_type}
275
- fields = method == "image_uri" ? fields.merge!({"attrib_type" => "blob.file"}) : fields
276
- result = ::Rhom::RhomDbAdapter::insert_into_table(::Rhom::TABLE_NAME, fields)
277
- end
278
- end
261
+ begin
262
+ ::Rhom::RhomDbAdapter.start_transaction
263
+
264
+ self.vars.each do |key,value|
265
+ val = self.inst_strip_braces(value)
266
+ # add rows excluding object, source_id and update_type
267
+ unless self.method_name_reserved?(key)
268
+ fields = {"source_id"=>self.get_inst_source_id,
269
+ "object"=>obj,
270
+ "attrib"=>key,
271
+ "value"=>val,
272
+ "update_type"=>update_type}
273
+ fields = key == "image_uri" ? fields.merge!({"attrib_type" => "blob.file"}) : fields
274
+ result = ::Rhom::RhomDbAdapter.insert_into_table('object_values', fields)
275
+ end
276
+ end
277
+
278
+ ::Rhom::RhomDbAdapter.commit
279
+
280
+ rescue Exception => e
281
+ ::Rhom::RhomDbAdapter.rollback
282
+ end
283
+
279
284
  result
280
285
  end
281
286
 
@@ -296,18 +301,13 @@ module Rhom
296
301
  # then we procede with update
297
302
  if old_val != new_val
298
303
  unless self.method_name_reserved?(attrib)
299
- ::Rhom::RhomDbAdapter::delete_from_table(::Rhom::TABLE_NAME,
300
- {"source_id"=>self.get_inst_source_id,
301
- "object"=>obj,
302
- "attrib"=>attrib,
303
- "update_type"=>update_type})
304
- # update sync list
305
- result = ::Rhom::RhomDbAdapter::insert_into_table(::Rhom::TABLE_NAME,
306
- {"source_id"=>self.get_inst_source_id,
307
- "object"=>obj,
308
- "attrib"=>attrib,
309
- "value"=>new_val,
310
- "update_type"=>update_type})
304
+ # only one update at a time
305
+ ::Rhom::RhomDbAdapter.delete_from_table('object_values', {"source_id"=>self.get_inst_source_id, "object"=>obj, "attrib"=>attrib, "update_type"=>update_type})
306
+ # add to syncengine queue
307
+ ::Rhom::RhomDbAdapter.insert_into_table('object_values', {"source_id"=>self.get_inst_source_id, "object"=>obj, "attrib"=>attrib, "value"=>new_val, "update_type"=>update_type})
308
+ # update viewable ('query') list
309
+ ::Rhom::RhomDbAdapter.delete_from_table('object_values', {"source_id"=>self.get_inst_source_id, "object"=>obj, "attrib"=>attrib, "update_type"=>'query'})
310
+ result = ::Rhom::RhomDbAdapter.insert_into_table('object_values', {"source_id"=>self.get_inst_source_id, "object"=>obj, "attrib"=>attrib, "value"=>new_val, "update_type"=>'query'})
311
311
  end
312
312
  end
313
313
  end
@@ -315,11 +315,11 @@ module Rhom
315
315
  end
316
316
 
317
317
  def get_inst_source_id
318
- Rho::RhoConfig::sources[self.class.name.to_s]['source_id'].to_s
318
+ Rho::RhoConfig.sources[self.class.name.to_s]['source_id'].to_s
319
319
  end
320
320
 
321
321
  def get_update_type_by_source(update_type)
322
- source_type = Rho::RhoConfig::sources[self.class.name.to_s]['type']
322
+ source_type = Rho::RhoConfig.sources[self.class.name.to_s]['type']
323
323
  if source_type and source_type == "ask" and update_type == 'delete'
324
324
  nil
325
325
  elsif source_type and source_type == "ask"