rhodes-framework 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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"