rhosync 2.0.0.beta3 → 2.0.0.beta4

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.
@@ -48,6 +48,50 @@ module Rhosync
48
48
  end
49
49
  counter
50
50
  end
51
+
52
+ # Loads data into fixed schema table based on source settings
53
+ def self.import_data_to_fixed_schema(db,source)
54
+ data = source.get_data(:md)
55
+ counter = {}
56
+ columns,qm = [],[]
57
+ create_table = ['object varchar']
58
+ schema = JSON.parse(source.schema)
59
+
60
+ db.transaction do |database|
61
+ # Create a table with columns specified by 'property' array in settings
62
+ schema['property'].each do |column|
63
+ create_table << "#{column.keys[0]} varchar default NULL"
64
+ columns << column.keys[0]
65
+ qm << '?'
66
+ end
67
+ database.execute("CREATE TABLE #{source.name}(
68
+ #{create_table.join(",")} );")
69
+
70
+ # Insert each object as single row in fixed schema table
71
+ database.prepare("insert into #{source.name}
72
+ (object,#{columns.join(',')}) values (?,#{qm.join(',')})") do |stmt|
73
+ data.each do |obj,row|
74
+ args = [obj]
75
+ columns.each do |col|
76
+ args << row[col]
77
+ end
78
+ stmt.execute(args)
79
+ end
80
+ end
81
+
82
+ # Create indexes for specified columns in settings 'index'
83
+ schema['index'].each do |index|
84
+ database.execute("CREATE INDEX #{index.keys[0]} on #{source.name} (#{index.values[0]});")
85
+ end if schema['index']
86
+
87
+ # Create unique indexes for specified columns in settings 'unique_index'
88
+ schema['unique_index'].each do |index|
89
+ database.execute("CREATE UNIQUE INDEX #{index.keys[0]} on #{source.name} (#{index.values[0]});")
90
+ end if schema['unique_index']
91
+ end
92
+
93
+ return {}
94
+ end
51
95
 
52
96
  def self.refs_to_s(refs)
53
97
  str = ''
@@ -84,7 +128,12 @@ module Rhosync
84
128
  :user_id => bulk_data.user_id})
85
129
  source.source_id = src_counter
86
130
  src_counter += 1
87
- source_attrib_refs = import_data_to_object_values(db,source)
131
+ source_attrib_refs = nil
132
+ if source.schema
133
+ source_attrib_refs = import_data_to_fixed_schema(db,source)
134
+ else
135
+ source_attrib_refs = import_data_to_object_values(db,source)
136
+ end
88
137
  sources_refs[source_name] =
89
138
  {:source => source, :refs => source_attrib_refs}
90
139
  lap_timer("finished importing sqlite data for #{source_name}",timer)
@@ -99,7 +148,7 @@ module Rhosync
99
148
  hsql_file = dbfile + ".hsqldb"
100
149
  raise Exception.new("Error running hsqldata") unless
101
150
  system('java','-cp', File.join(File.dirname(__FILE__),'..','..','..','vendor','hsqldata.jar'),
102
- 'com.rhomobile.hsqldata.HsqlData', dbfile, hsql_file, schema, index)
151
+ 'com.rhomobile.hsqldata.HsqlData', dbfile, hsql_file)
103
152
  end
104
153
 
105
154
  def self.get_file_args(bulk_data_name,ts)
@@ -112,10 +112,6 @@ module Rhosync
112
112
  params[:source_name] ? {:source_name => current_source.name} : {:source_name => '*'})
113
113
  end
114
114
  end
115
-
116
- def source_config
117
- { "sources" => Rhosync.get_config(Rhosync.base_directory)[:sources] }
118
- end
119
115
 
120
116
  def catch_all
121
117
  begin
@@ -136,15 +132,21 @@ module Rhosync
136
132
  Rhosync.log "Rhosync Server v#{Rhosync::VERSION} started..."
137
133
 
138
134
  before do
139
- if params["cud"]
140
- cud = JSON.parse(params["cud"])
141
- params.delete("cud")
142
- params.merge!(cud)
143
- end
144
- if request.env['CONTENT_TYPE'] == 'application/json'
145
- params.merge!(JSON.parse(request.body.read))
146
- request.body.rewind
147
- end
135
+ begin
136
+ if params["cud"]
137
+ cud = JSON.parse(params["cud"])
138
+ params.delete("cud")
139
+ params.merge!(cud)
140
+ end
141
+ if request.env['CONTENT_TYPE'] == 'application/json'
142
+ params.merge!(JSON.parse(request.body.read))
143
+ request.body.rewind
144
+ end
145
+ rescue JSON::ParserError => jpe
146
+ throw :halt, [500, "Server error while processing client data"]
147
+ rescue Exception => e
148
+ throw :halt, [500, "Internal server error"]
149
+ end
148
150
  if params[:version] and params[:version].to_i < 3
149
151
  throw :halt, [404, "Server supports version 3 or higher of the protocol."]
150
152
  end
@@ -13,6 +13,7 @@ module Rhosync
13
13
  field :queue,:string
14
14
  field :query_queue,:string
15
15
  field :cud_queue,:string
16
+ field :schema, :string
16
17
  attr_accessor :app_id, :user_id
17
18
  validates_presence_of :name #, :source_id
18
19
 
@@ -27,6 +28,7 @@ module Rhosync
27
28
  fields[:partition_type] ||= :user
28
29
  fields[:poll_interval] ||= 300
29
30
  fields[:sync_type] ||= :incremental
31
+ fields[:schema] = fields[:schema].to_json if fields[:schema]
30
32
  end
31
33
 
32
34
  def self.create(fields,params)
@@ -43,6 +45,7 @@ module Rhosync
43
45
  end
44
46
 
45
47
  def update(fields)
48
+ fields = fields.with_indifferent_access # so we can access hash keys as symbols
46
49
  self.class.set_defaults(fields)
47
50
  super(fields)
48
51
  end
@@ -4,6 +4,8 @@ module Rhosync
4
4
  end
5
5
 
6
6
  module TestMethods
7
+ # Initializes the source adapter under test for a given user, typically in a before(:each) block
8
+ # setup_test_for(Product,'testuser') #=> 'testuser' will be used by rest of the specs
7
9
  def setup_test_for(adapter,user_id)
8
10
  app_id = 'application'
9
11
  s_fields = {
@@ -23,15 +25,51 @@ module Rhosync
23
25
  @ss = SourceSync.new(@s)
24
26
  end
25
27
 
28
+ # Executes the adapter's query method and returns
29
+ # the master document (:md) stored in redis
30
+ # For example, if your source adapter query method was:
31
+ # def query(params=nil)
32
+ # @result = {
33
+ # "1"=>{"name"=>"Acme", "industry"=>"Electronics"},
34
+ # "2"=>{"name"=>"Best", "industry"=>"Software"}
35
+ # }
36
+ # end
37
+ #
38
+ # test_query would return:
39
+ # {
40
+ # "1"=>{"name"=>"Acme", "industry"=>"Electronics"},
41
+ # "2"=>{"name"=>"Best", "industry"=>"Software"}
42
+ # }
26
43
  def test_query
27
44
  @ss.process_query
28
45
  return md
29
46
  end
30
47
 
48
+ # Returns any errors stored in redis for the previous source adapter query
49
+ # For example: {"query-error"=>{"message"=>"error connecting to web service!"}}
31
50
  def query_errors
32
51
  @s.get_data(:errors)
33
52
  end
34
53
 
54
+ # Execute's the adapter's create method with a provided record and
55
+ # returns the object string from the create method. If the create method
56
+ # returns a string, then a link will be saved for the device next time
57
+ # it synchronizes. This link can be tested here.
58
+ #
59
+ # For example, in your spec:
60
+ # @product = {
61
+ # 'name' => 'iPhone',
62
+ # 'brand' => 'Apple',
63
+ # 'price' => '$299.99',
64
+ # 'quantity' => '5',
65
+ # 'sku' => '1234'
66
+ # }
67
+ # new_product_id = test_create(@product)
68
+ # create_errors.should == {}
69
+ # md[new_product_id].should == @product
70
+ #
71
+ # This will return the result of the adapter's create method. The master
72
+ # document (:md) should also contain the new record.
35
73
  def test_create(record)
36
74
  @c.put_data(:create,{'temp-id' => record})
37
75
  @ss.create(@c.id)
@@ -39,32 +77,72 @@ module Rhosync
39
77
  links ? links['l'] : nil
40
78
  end
41
79
 
80
+ # Returns any errors stored in redis from the previous source adapter create
81
+ # (same structure as query errors)
42
82
  def create_errors
43
83
  @c.get_data(:create_errors)
44
84
  end
45
85
 
86
+ # Execute the source adapter's update method.
87
+ # Takes a record as hash of hashes (object_id => object)
88
+ #
89
+ # For example:
90
+ # test_update({'4' => {'price' => '$199.99'}})
91
+ # update_errors.should == {}
92
+ # test_query
93
+ # md[product_id]['price'].should == '$199.99'
94
+ #
95
+ # This will call the adapter's update method for object_id '4'
96
+ # NOTE: To test the master document, you will need to run def test_query
97
+ # as shown above
46
98
  def test_update(record)
47
99
  @c.put_data(:update,record)
48
100
  @ss.update(@c.id)
49
101
  end
50
102
 
103
+ # Returns any errors stored in redis from the previous source adapter update
104
+ # (same structure as query errors)
51
105
  def update_errors
52
106
  @c.get_data(:update_errors)
53
107
  end
54
108
 
109
+ # Execute the source adapter's delete method.
110
+ # Takes a record as hash of hashes (object_id => object)
111
+ #
112
+ # For example:
113
+ # @product = {
114
+ # 'name' => 'iPhone',
115
+ # 'brand' => 'Apple',
116
+ # 'price' => '$299.99',
117
+ # 'quantity' => '5',
118
+ # 'sku' => '1234'
119
+ # }
120
+ # test_delete('4' => @product)
121
+ # delete_errors.should == {}
122
+ # md.should == {}
123
+ #
124
+ # This will call the adapter's delete method for product '4'
125
+ # NOTE: The master document (:md) will be updated and can be
126
+ # verified as shown above.
55
127
  def test_delete(record)
56
128
  @c.put_data(:delete,record)
57
129
  @ss.delete(@c.id)
58
130
  end
59
131
 
132
+ # Returns any errors stored in redis from the previous source adapter delete
133
+ # (same structure as query errors)
60
134
  def delete_errors
61
135
  @c.get_data(:delete_errors)
62
136
  end
63
137
 
138
+ # Returns the master document (:md) for the source adapter stored in redis.
139
+ # This is equivalent to the @result hash of hashes structure.
64
140
  def md
65
141
  @s.get_data(:md)
66
142
  end
67
143
 
144
+ # Returns the client document (:cd) for the source adapter + client under test.
145
+ # The master document (:md) and client document (:cd) should be equal
68
146
  def cd
69
147
  @c.get_data(:cd)
70
148
  end
@@ -1,3 +1,3 @@
1
1
  module Rhosync
2
- VERSION = '2.0.0.beta3'
2
+ VERSION = '2.0.0.beta4'
3
3
  end
data/lib/rhosync.rb CHANGED
@@ -122,6 +122,10 @@ module Rhosync
122
122
  settings_file = File.join(basedir,'settings','settings.yml') if basedir
123
123
  YAML.load_file(settings_file) if settings_file and File.exist?(settings_file)
124
124
  end
125
+
126
+ def source_config
127
+ { "sources" => Rhosync.get_config(Rhosync.base_directory)[:sources] }
128
+ end
125
129
  ### End Rhosync setup methods
126
130
 
127
131
 
@@ -19,7 +19,8 @@ describe "RhosyncApiGetSourceParams" do
19
19
  {"name"=>"sync_type", "value"=>"incremental", "type"=>"string"},
20
20
  {"name"=>"queue", "value"=>nil, "type"=>"string"},
21
21
  {"name"=>"query_queue", "value"=>nil, "type"=>"string"},
22
- {"name"=>"cud_queue", "value"=>nil, "type"=>"string"}]
22
+ {"name"=>"cud_queue", "value"=>nil, "type"=>"string"},
23
+ {"name"=>"schema", "value"=>nil, "type"=>"string"}]
23
24
  end
24
25
 
25
26
  end
@@ -5,13 +5,13 @@ describe "RhosyncApiListSources" do
5
5
 
6
6
  it "should list all application sources" do
7
7
  post "/api/list_sources", {:api_token => @api_token}
8
- JSON.parse(last_response.body).should == ["SimpleAdapter", "SampleAdapter"]
8
+ JSON.parse(last_response.body).sort.should == ["SimpleAdapter", "SampleAdapter", "FixedSchemaAdapter"].sort
9
9
  end
10
10
 
11
11
  it "should list all application sources using partition_type param" do
12
12
  post "/api/list_sources",
13
13
  {:api_token => @api_token, :partition_type => 'all'}
14
- JSON.parse(last_response.body).should == ["SimpleAdapter", "SampleAdapter"]
14
+ JSON.parse(last_response.body).sort.should == ["SimpleAdapter", "SampleAdapter", "FixedSchemaAdapter"].sort
15
15
  end
16
16
 
17
17
  it "should list app partition sources" do
@@ -21,7 +21,7 @@ describe "RhosyncApiListSources" do
21
21
 
22
22
  it "should list user partition sources" do
23
23
  post "/api/list_sources", {:api_token => @api_token, :partition_type => :user}
24
- JSON.parse(last_response.body).should == ["SampleAdapter"]
24
+ JSON.parse(last_response.body).sort.should == ["SampleAdapter", "FixedSchemaAdapter"].sort
25
25
  end
26
26
 
27
27
  end
@@ -4,6 +4,19 @@
4
4
  SimpleAdapter:
5
5
  poll_interval: 600
6
6
  partition_type: app
7
+ FixedSchemaAdapter:
8
+ poll_interval: 300
9
+ schema:
10
+ version: '1.0'
11
+ property:
12
+ - name: string
13
+ - brand: string
14
+ - price: string
15
+ - image_url: blob
16
+ index:
17
+ - by_name_brand: 'name,brand'
18
+ unique_index:
19
+ - by_price: 'price'
7
20
 
8
21
  :development:
9
22
  :licensefile: settings/license.key
@@ -0,0 +1,9 @@
1
+ class FixedSchemaAdapter < SourceAdapter
2
+ def initialize(source,credential)
3
+ super(source,credential)
4
+ end
5
+
6
+ def query(params=nil)
7
+ @result = Store.get_data('test_db_storage')
8
+ end
9
+ end
data/spec/doc/doc_spec.rb CHANGED
@@ -28,8 +28,6 @@ describe "Protocol" do
28
28
  :run => false,
29
29
  :secret => "secure!"
30
30
  )
31
- Server.use Rack::Static, :urls => ["/data"],
32
- :root => File.join(File.dirname(__FILE__),'..','apps',@test_app_name)
33
31
  end
34
32
 
35
33
  before(:each) do
@@ -16,16 +16,19 @@ describe "BulkDataJob" do
16
16
  it "should create sqlite data file from master document" do
17
17
  set_state('test_db_storage' => @data)
18
18
  docname = bulk_data_docname(@a.id,@u.id)
19
+ expected = { @s_fields[:name] => @data,
20
+ 'FixedSchemaAdapter' => @data
21
+ }
19
22
  data = BulkData.create(:name => docname,
20
23
  :state => :inprogress,
21
24
  :app_id => @a.id,
22
25
  :user_id => @u.id,
23
- :sources => [@s_fields[:name]])
26
+ :sources => [@s_fields[:name], 'FixedSchemaAdapter'])
24
27
  BulkDataJob.perform("data_name" => data.name)
25
28
  data = BulkData.load(docname)
26
29
  data.completed?.should == true
27
30
  verify_result(@s.docname(:md) => @data,@s.docname(:md_copy) => @data)
28
- validate_db(data,@data).should == true
31
+ validate_db(data,expected).should == true
29
32
  File.exists?(data.dbfile+'.rzip').should == true
30
33
  File.exists?(data.dbfile+'.hsqldb.data').should == true
31
34
  File.exists?(data.dbfile+'.hsqldb.script').should == true
@@ -33,7 +36,8 @@ describe "BulkDataJob" do
33
36
  path = File.join(File.dirname(data.dbfile),'tmp')
34
37
  FileUtils.mkdir_p path
35
38
  unzip_file("#{data.dbfile}.rzip",path)
36
- validate_db_by_name(File.join(path,File.basename(data.dbfile)),@data)
39
+ data.dbfile = File.join(path,File.basename(data.dbfile))
40
+ validate_db(data,expected).should == true
37
41
  end
38
42
 
39
43
  it "should not create hsql db files if blackberry_bulk_sync is disabled" do
@@ -49,11 +53,11 @@ describe "BulkDataJob" do
49
53
  data = BulkData.load(docname)
50
54
  data.completed?.should == true
51
55
  verify_result(@s.docname(:md) => @data,@s.docname(:md_copy) => @data)
52
- validate_db(data,@data).should == true
56
+ validate_db(data,@s.name => @data).should == true
53
57
  File.exists?(data.dbfile+'.hsqldb.script').should == false
54
58
  File.exists?(data.dbfile+'.hsqldb.properties').should == false
55
59
  end
56
-
60
+
57
61
  it "should create sqlite data with source metadata" do
58
62
  set_state('test_db_storage' => @data)
59
63
  mock_metadata_method([SampleAdapter]) do
@@ -69,7 +73,7 @@ describe "BulkDataJob" do
69
73
  verify_result(@s.docname(:md) => @data,
70
74
  @s.docname(:metadata) => {'foo'=>'bar'}.to_json,
71
75
  @s.docname(:md_copy) => @data)
72
- validate_db(data,@data).should == true
76
+ validate_db(data,@s.name => @data).should == true
73
77
  end
74
78
  end
75
79
 
@@ -13,6 +13,8 @@ describe "Server" do
13
13
  include Rack::Test::Methods
14
14
  include Rhosync
15
15
 
16
+ it_should_behave_like "DBObjectsHelper"
17
+
16
18
  before(:each) do
17
19
  require File.join(get_testapp_path,@test_app_name)
18
20
  Rhosync.bootstrap(get_testapp_path) do |rhosync|
@@ -24,14 +26,12 @@ describe "Server" do
24
26
  :secret => "secure!"
25
27
  )
26
28
  Server.use Rack::Static, :urls => ["/data"],
27
- :root => File.join(File.dirname(__FILE__),'..','apps','rhotestapp')
29
+ :root => File.expand_path(File.join(File.dirname(__FILE__),'..','apps','rhotestapp'))
28
30
  end
29
31
 
30
32
  def app
31
33
  @app ||= Server.new
32
34
  end
33
-
34
- it_should_behave_like "DBObjectsHelper"
35
35
 
36
36
  it "should show status page" do
37
37
  get '/'
@@ -116,8 +116,19 @@ describe "Server" do
116
116
  describe "client management routes" do
117
117
  before(:each) do
118
118
  do_post "/application/clientlogin", "login" => @u.login, "password" => 'testpass'
119
- @source_config = {"sources"=>{"SampleAdapter"=>{"poll_interval"=>300},
120
- "SimpleAdapter"=>{"partition_type"=>"app","poll_interval"=>600}}}
119
+ @source_config = {
120
+ "sources"=> {
121
+ "FixedSchemaAdapter"=>
122
+ {"schema"=>{"property"=>[{"name"=>"string"},
123
+ {"brand"=>"string"}, {"price"=>"string"},
124
+ {"image_url"=>"blob"}], "version"=>"1.0",
125
+ "unique_index"=>[{"by_price"=>"price"}],
126
+ "index"=>[{"by_name_brand"=>"name,brand"}]},
127
+ "poll_interval"=>300},
128
+ "SampleAdapter"=>{"poll_interval"=>300},
129
+ "SimpleAdapter"=>{"partition_type"=>"app",
130
+ "poll_interval"=>600}}
131
+ }
121
132
  end
122
133
 
123
134
  it "should respond to clientcreate" do
@@ -190,6 +201,20 @@ describe "Server" do
190
201
  verify_result("test_delete_storage" => {'1'=>@product1})
191
202
  end
192
203
 
204
+ it "should handle client posting broken json" do
205
+ broken_json = "{\"foo\":\"bar\"\"}"
206
+ post "/application", broken_json, {'CONTENT_TYPE'=>'application/json'}
207
+ last_response.status.should == 500
208
+ last_response.body.should == "Server error while processing client data"
209
+ end
210
+
211
+ it "should handle client posting broken body" do
212
+ broken_json = ['foo']
213
+ post "/application", broken_json, {'CONTENT_TYPE'=>'application/json'}
214
+ last_response.status.should == 500
215
+ last_response.body.should == "Internal server error"
216
+ end
217
+
193
218
  it "should get inserts json" do
194
219
  cs = ClientSync.new(@s,@c,1)
195
220
  data = {'1'=>@product1,'2'=>@product2}
@@ -307,7 +332,7 @@ describe "Server" do
307
332
  data = BulkData.load(bulk_data_docname(@a.id,@u.id))
308
333
  last_response.body.should == {:result => :url,
309
334
  :url => data.url}.to_json
310
- validate_db_by_name(data.dbfile,@data)
335
+ validate_db(data,{@s.name => @data, 'FixedSchemaAdapter' => @data})
311
336
  end
312
337
 
313
338
  it "should download bulk data file" do
@@ -318,7 +343,7 @@ describe "Server" do
318
343
  get JSON.parse(last_response.body)["url"]
319
344
  last_response.should be_ok
320
345
  File.open('test.data','wb') {|f| f.puts last_response.body}
321
- validate_db_by_name('test.data',@data)
346
+ validate_db_file('test.data',[@s.name,'FixedSchemaAdapter'],{@s.name => @data, 'FixedSchemaAdapter' => @data})
322
347
  File.delete('test.data')
323
348
  end
324
349
 
data/spec/spec_helper.rb CHANGED
@@ -58,6 +58,10 @@ module TestHelpers
58
58
  def delete_data_directory
59
59
  FileUtils.rm_rf(Rhosync.data_directory)
60
60
  end
61
+
62
+ def json_clone(data)
63
+ JSON.parse(data.to_json)
64
+ end
61
65
 
62
66
  def set_state(state)
63
67
  state.each do |dockey,data|
@@ -97,26 +101,52 @@ module TestHelpers
97
101
  end
98
102
 
99
103
  def validate_db(bulk_data,data)
100
- validate_db_by_name(bulk_data.dbfile,data)
104
+ validate_db_file(bulk_data.dbfile,bulk_data.sources.members,data)
105
+ end
106
+
107
+ def validate_db_file(dbfile,sources,data)
108
+ db = SQLite3::Database.new(dbfile)
109
+ sources.each do |source_name|
110
+ s = Source.load(source_name,{:app_id => APP_NAME,:user_id => @u.login})
111
+ return false unless validate_db_by_name(db,s,data[s.name])
112
+ end
113
+ true
101
114
  end
102
115
 
103
- def validate_db_by_name(name,data)
104
- db = SQLite3::Database.new(name)
105
- db.execute("select source_id,name,sync_priority,partition,sync_type,source_attribs,metadata from sources").each do |row|
106
- return false if row[0] != @s.source_id.to_s
107
- return false if row[1] != @s.name
108
- return false if row[2] != @s.priority.to_s
109
- return false if row[3] != @s.partition_type.to_s
110
- return false if row[4] != @s.sync_type.to_s
111
- return false if row[5] != get_attrib_counter(data)
112
- return false if row[6] != @s.get_value(:metadata)
116
+ def validate_db_by_name(db,s,data)
117
+ db.execute("select source_id,name,sync_priority,partition,
118
+ sync_type,source_attribs,metadata from sources where name='#{s.name}'").each do |row|
119
+ return false if row[0] != s.source_id.to_s
120
+ return false if row[1] != s.name
121
+ return false if row[2] != s.priority.to_s
122
+ return false if row[3] != s.partition_type.to_s
123
+ return false if row[4] != s.sync_type.to_s
124
+ return false if row[5] != (s.schema ? "" : get_attrib_counter(data))
125
+ return false if row[6] != s.get_value(:metadata)
126
+ end
127
+ data = json_clone(data)
128
+ if s.schema
129
+ schema = JSON.parse(s.schema)
130
+ columns = ['object']
131
+ schema['property'].each do |column|
132
+ columns << column.keys[0]
133
+ end
134
+ db.execute("select #{columns.join(',')} from #{s.name}") do |row|
135
+ obj = data[row[0]]
136
+ columns.each_index do |i|
137
+ next if i == 0
138
+ return false if row[i] != obj[columns[i]]
139
+ end
140
+ data.delete(row[0])
141
+ end
142
+ else
143
+ db.execute("select * from object_values where source_id=#{s.source_id}").each do |row|
144
+ object = data[row[2]]
145
+ return false if object.nil? or object[row[1]] != row[3] or row[0] != s.source_id.to_s
146
+ object.delete(row[1])
147
+ data.delete(row[2]) if object.empty?
148
+ end
113
149
  end
114
- db.execute("select * from object_values").each do |row|
115
- object = data[row[2]]
116
- return false if object.nil? or object[row[1]] != row[3] or row[0] != @s.source_id.to_s
117
- object.delete(row[1])
118
- data.delete(row[2]) if object.empty?
119
- end
120
150
  data.empty?
121
151
  end
122
152
 
@@ -232,6 +262,10 @@ describe "DBObjectsHelper", :shared => true do
232
262
  @c = Client.create(@c_fields,{:source_name => @s_fields[:name]})
233
263
  @s = Source.load(@s_fields[:name],@s_params)
234
264
  @s = Source.create(@s_fields,@s_params) if @s.nil?
265
+ @s1 = Source.load('FixedSchemaAdapter',@s_params)
266
+ @s1 = Source.create({:name => 'FixedSchemaAdapter'},@s_params) if @s1.nil?
267
+ config = Rhosync.source_config["sources"]['FixedSchemaAdapter']
268
+ @s1.update(config)
235
269
  @r = @s.read_state
236
270
  @a.sources << @s.id
237
271
  @a.users << @u.id
metadata CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 2
7
7
  - 0
8
8
  - 0
9
- - beta3
10
- version: 2.0.0.beta3
9
+ - beta4
10
+ version: 2.0.0.beta4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Rhomobile
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-05-18 00:00:00 -07:00
18
+ date: 2010-05-20 00:00:00 -07:00
19
19
  default_executable: rhosync
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -412,6 +412,7 @@ files:
412
412
  - spec/apps/rhotestapp/settings/license.key
413
413
  - spec/apps/rhotestapp/settings/settings.yml
414
414
  - spec/apps/rhotestapp/sources/base_adapter.rb
415
+ - spec/apps/rhotestapp/sources/fixed_schema_adapter.rb
415
416
  - spec/apps/rhotestapp/sources/sample_adapter.rb
416
417
  - spec/apps/rhotestapp/sources/simple_adapter.rb
417
418
  - spec/apps/rhotestapp/sources/sub_adapter.rb
@@ -513,6 +514,7 @@ test_files:
513
514
  - spec/app_spec.rb
514
515
  - spec/apps/rhotestapp/application.rb
515
516
  - spec/apps/rhotestapp/sources/base_adapter.rb
517
+ - spec/apps/rhotestapp/sources/fixed_schema_adapter.rb
516
518
  - spec/apps/rhotestapp/sources/sample_adapter.rb
517
519
  - spec/apps/rhotestapp/sources/simple_adapter.rb
518
520
  - spec/apps/rhotestapp/sources/sub_adapter.rb