couch_tap 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,32 @@
1
+ module CouchTap
2
+
3
+ # Wrapper around a sequel table definition
4
+ # to allow easy access to column names.
5
+ class Schema
6
+
7
+ attr_accessor :name, :database, :columns, :column_names
8
+
9
+ def initialize(database, name)
10
+ self.name = name.to_sym
11
+ self.database = database
12
+ self.columns = {}
13
+ self.column_names = []
14
+ parse_schema
15
+ end
16
+
17
+ def dataset
18
+ database[name]
19
+ end
20
+
21
+ protected
22
+
23
+ def parse_schema
24
+ database.schema(name).each do |row|
25
+ column_names << row[0]
26
+ columns[row[0]] = row[1]
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,37 @@
1
+ require '../test_helper'
2
+
3
+ class FunctionalChangesTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ # Create a new CouchDB
7
+ @source = CouchRest.database('couch_tap')
8
+ create_sample_documents
9
+
10
+ # Create a new Sqlite DB in memory
11
+ @database = Sequel.sqlite
12
+ migrate_sample_database
13
+ end
14
+
15
+ def test_something
16
+ assert_equal "foo", "bar"
17
+ end
18
+
19
+
20
+ protected
21
+
22
+ def migrate_sample_database
23
+ @database.create_table :items do
24
+ primary_key :id
25
+ String :name
26
+ Float :price
27
+ Time :created_at
28
+ end
29
+ end
30
+
31
+ def create_sample_documents
32
+ @source.save_doc {:name => "Item 1", :price => 1.23, :created_at => Time.now}
33
+ @source.save_doc {:name => "Item 2", :price => 2.23, :created_at => Time.now}
34
+ @source.save_doc {:name => "Item 3", :price => 3.23, :created_at => Time.now}
35
+ end
36
+
37
+ end
@@ -0,0 +1,16 @@
1
+
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
4
+
5
+ require 'test/unit'
6
+ require 'mocha/setup'
7
+ require 'couch_tap'
8
+
9
+ TEST_DB_HOST = 'http://127.0.0.1:5984/'
10
+ TEST_DB_NAME = 'couch_tap'
11
+ TEST_DB_ROOT = File.join(TEST_DB_HOST, TEST_DB_NAME)
12
+ TEST_DB = CouchRest.database(TEST_DB_ROOT)
13
+
14
+ def reset_test_db!
15
+ TEST_DB.recreate!
16
+ end
@@ -0,0 +1,74 @@
1
+ require 'test_helper'
2
+
3
+ module Builders
4
+ class CollectionTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @parent = mock()
8
+ end
9
+
10
+ def test_initialize_collection
11
+ @collection = CouchTap::Builders::Collection.new(@parent, :items) do
12
+ # nothing
13
+ end
14
+ assert_equal @collection.parent, @parent
15
+ assert_equal @collection.field, :items
16
+ end
17
+
18
+ def test_raise_error_if_no_block
19
+ assert_raise ArgumentError do
20
+ @collection = CouchTap::Builders::Collection.new(@parent, :items)
21
+ end
22
+ end
23
+
24
+ def test_defining_table
25
+ @parent.expects(:data).returns({'items' => []})
26
+ @collection = CouchTap::Builders::Collection.new(@parent, :items) do
27
+ table :invoice_items do
28
+ # nothing
29
+ end
30
+ end
31
+ end
32
+
33
+ def test_defining_table_with_items
34
+ @parent.expects(:data).returns({'items' => [{'name' => 'Item 1'}]})
35
+ block = lambda do
36
+ # nothing
37
+ end
38
+ CouchTap::Builders::Table.expects(:new).with(@parent, :invoice_items, {:data => {'name' => 'Item 1'}}, &block)
39
+ @collection = CouchTap::Builders::Collection.new(@parent, :items) do
40
+ table :invoice_items, &block
41
+ end
42
+ end
43
+
44
+ def test_defining_table_with_items
45
+ @parent.expects(:data).returns({'items' => [{:name => 'Item 1'}, {:name => 'Item 2'}]})
46
+ CouchTap::Builders::Table.expects(:new).twice
47
+ @collection = CouchTap::Builders::Collection.new(@parent, :items) do
48
+ table :invoice_items
49
+ end
50
+ end
51
+
52
+ def test_defining_table_with_null_data
53
+ assert_nothing_raised do
54
+ @parent.expects(:data).returns({'items' => nil})
55
+ CouchTap::Builders::Table.expects(:new).never
56
+ @collection = CouchTap::Builders::Collection.new(@parent, :items) do
57
+ table :invoice_items
58
+ end
59
+ end
60
+ end
61
+
62
+ def test_execution
63
+ @table = mock()
64
+ CouchTap::Builders::Table.expects(:new).twice.returns(@table)
65
+ @parent.expects(:data).returns({'items' => [{:name => 'Item 1'}, {:name => 'Item 2'}]})
66
+ @collection = CouchTap::Builders::Collection.new(@parent, :items) do
67
+ table :invoice_items
68
+ end
69
+ @table.expects(:execute).twice
70
+ @collection.execute
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,259 @@
1
+ require 'test_helper'
2
+
3
+ module Builders
4
+ class TableTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @database = create_database
8
+ @changes = mock()
9
+ @changes.stubs(:database).returns(@database)
10
+ @changes.stubs(:schema).returns(CouchTap::Schema.new(@database, :items))
11
+ @handler = CouchTap::DocumentHandler.new(@changes)
12
+ end
13
+
14
+ def test_init
15
+ doc = CouchRest::Document.new({'type' => 'Item', 'name' => "Some Item", '_id' => '1234'})
16
+ @handler.document = doc
17
+ @row = CouchTap::Builders::Table.new(@handler, 'items')
18
+
19
+ assert_equal @row.parent, @handler
20
+ assert_equal @row.handler, @handler
21
+ assert_equal @row.document, doc
22
+ assert_equal @row.name, :items
23
+
24
+ assert_equal @row.primary_keys, [:item_id]
25
+
26
+ # Also confirm that the automated calls were made
27
+ assert_equal @row.attributes[:name], 'Some Item'
28
+ assert_nil @row.attributes[:type]
29
+ assert_nil @row.attributes[:_id]
30
+ assert_equal @row.attributes[:item_id], '1234'
31
+
32
+ assert_equal @row.instance_eval("@_collections.length"), 0
33
+ end
34
+
35
+ def test_init_with_data
36
+ doc = CouchRest::Document.new({'type' => 'Group', 'name' => "Some Group", '_id' => '1234',
37
+ 'items' => [{'index' => 1, 'name' => 'Item 1'}]})
38
+ @handler.document = doc
39
+ @parent = CouchTap::Builders::Table.new(@handler, 'groups')
40
+ @row = CouchTap::Builders::Table.new(@parent, 'items', :data => doc['items'][0])
41
+
42
+ assert_equal @row.parent, @parent
43
+ assert_equal @row.handler, @handler
44
+ assert_equal @row.document, doc
45
+ assert_equal @row.data, doc['items'][0]
46
+
47
+ assert_equal @row.primary_keys, [:group_id, :item_id]
48
+ assert_equal @row.attributes[:name], 'Item 1'
49
+ end
50
+
51
+ def test_init_with_primary_key
52
+ doc = {'type' => 'Item', 'name' => "Some Item", '_id' => '1234'}
53
+ @handler.document = doc
54
+ @row = CouchTap::Builders::Table.new(@handler, :items, :primary_key => :entry_id)
55
+
56
+ assert_equal @row.primary_keys, [:entry_id]
57
+ end
58
+
59
+ def test_init_with_data_string
60
+ create_many_to_many_items
61
+ doc = {'type' => 'Item', 'name' => "Some Group", '_id' => '1234',
62
+ 'item_ids' => ['i1234', 'i1235']}
63
+ @handler.document = doc
64
+ @parent = CouchTap::Builders::Table.new(@handler, 'groups')
65
+ @row = CouchTap::Builders::Table.new(@parent, :group_items, :primary_key => false, :data => doc['item_ids'][0]) do
66
+ column :item_id, data
67
+ end
68
+ @row.execute
69
+ assert_equal @database[:group_items].first, {:group_id => '1234', :item_id => 'i1234'}
70
+ end
71
+
72
+ def test_execute_with_new_row
73
+ doc = {'type' => 'Item', 'name' => "Some Item", '_id' => '1234'}
74
+ @handler.document = doc
75
+ @row = CouchTap::Builders::Table.new(@handler, :items)
76
+ @row.execute
77
+
78
+ items = @database[:items]
79
+ item = items.first
80
+ assert_equal items.where(:item_id => '1234').count, 1
81
+ assert_equal item[:name], "Some Item"
82
+ end
83
+
84
+ def test_execute_with_new_row_with_time
85
+ time = Time.now
86
+ doc = {'type' => 'Item', 'name' => "Some Item", '_id' => '1234', 'created_at' => time.to_s}
87
+ @handler.document = doc
88
+ @row = CouchTap::Builders::Table.new(@handler, :items)
89
+ @row.execute
90
+ items = @database[:items]
91
+ item = items.first
92
+ assert item[:created_at].is_a?(Time)
93
+ assert_equal item[:created_at].to_s, time.to_s
94
+ end
95
+
96
+ def test_building_collections
97
+ doc = {'type' => 'Item', 'name' => "Some Group", '_id' => '1234',
98
+ 'items' => [{'index' => 1, 'name' => 'Item 1'}]}
99
+ @handler.document = doc
100
+ @row = CouchTap::Builders::Table.new @handler, :group do
101
+ collection :items do
102
+ # Nothing
103
+ end
104
+ end
105
+ assert_equal @row.instance_eval("@_collections.length"), 1
106
+ end
107
+
108
+ def test_collections_are_executed
109
+ @database.create_table :groups do
110
+ String :group_id
111
+ String :name
112
+ end
113
+ doc = {'type' => 'Item', 'name' => "Some Group", '_id' => '1234',
114
+ 'items' => [{'index' => 1, 'name' => 'Item 1'}]}
115
+ @handler.document = doc
116
+ @row = CouchTap::Builders::Table.new @handler, :groups do
117
+ collection :items do
118
+ # Nothing
119
+ end
120
+ end
121
+ @row.instance_eval("@_collections.first.expects(:execute)")
122
+ @row.execute
123
+ end
124
+
125
+
126
+ def test_column_assign_with_symbol
127
+ doc = {'type' => 'Item', 'full_name' => "Some Other Item", '_id' => '1234'}
128
+ @handler.document = doc
129
+ @row = CouchTap::Builders::Table.new @handler, :items do
130
+ column :name, :full_name
131
+ end
132
+ @row.execute
133
+
134
+ data = @database[:items].first
135
+ assert_equal data[:name], doc['full_name']
136
+ end
137
+
138
+ def test_column_assign_with_value
139
+ doc = {'type' => 'Item', '_id' => '1234'}
140
+ @handler.document = doc
141
+ @row = CouchTap::Builders::Table.new @handler, :items do
142
+ column :name, "Force the name"
143
+ end
144
+ @row.execute
145
+
146
+ data = @database[:items].first
147
+ assert_equal data[:name], "Force the name"
148
+ end
149
+
150
+ def test_column_assign_with_nil
151
+ doc = {'type' => 'Item', 'name' => 'Some Item Name', '_id' => '1234'}
152
+ @handler.document = doc
153
+ @row = CouchTap::Builders::Table.new @handler, :items do
154
+ column :name, nil
155
+ end
156
+ @row.execute
157
+ data = @database[:items].first
158
+ assert_equal data[:name], nil
159
+ end
160
+
161
+ def test_column_assign_with_empty_for_non_string
162
+ doc = {'type' => 'Item', 'name' => 'Some Item Name', 'created_at' => '', '_id' => '1234'}
163
+ @handler.document = doc
164
+ @row = CouchTap::Builders::Table.new @handler, :items
165
+ @row.execute
166
+ data = @database[:items].first
167
+ assert_equal data[:created_at], nil
168
+ end
169
+
170
+ def test_column_assign_with_integer
171
+ doc = {'type' => 'Item', 'count' => 3, '_id' => '1234'}
172
+ @handler.document = doc
173
+ @row = CouchTap::Builders::Table.new @handler, :items
174
+ @row.execute
175
+ data = @database[:items].first
176
+ assert_equal data[:count], 3
177
+ end
178
+
179
+ def test_column_assign_with_integer_as_string
180
+ doc = {'type' => 'Item', 'count' => '1', '_id' => '1234'}
181
+ @handler.document = doc
182
+ @row = CouchTap::Builders::Table.new @handler, :items
183
+ @row.execute
184
+ data = @database[:items].first
185
+ assert_equal data[:count], 1
186
+ end
187
+
188
+ def test_column_assign_with_float
189
+ doc = {'type' => 'Item', 'price' => 1.2, '_id' => '1234'}
190
+ @handler.document = doc
191
+ @row = CouchTap::Builders::Table.new @handler, :items
192
+ @row.execute
193
+ data = @database[:items].first
194
+ assert_equal data[:price], 1.2
195
+ end
196
+
197
+
198
+ def test_column_assign_with_float_as_string
199
+ doc = {'type' => 'Item', 'price' => '1.2', '_id' => '1234'}
200
+ @handler.document = doc
201
+ @row = CouchTap::Builders::Table.new @handler, :items
202
+ @row.execute
203
+ data = @database[:items].first
204
+ assert_equal data[:price], 1.2
205
+ end
206
+
207
+
208
+ def test_column_assign_with_block
209
+ doc = {'type' => 'Item', '_id' => '1234'}
210
+ @handler.document = doc
211
+ @row = CouchTap::Builders::Table.new @handler, :items do
212
+ column :name do
213
+ "Name from block"
214
+ end
215
+ end
216
+ @row.execute
217
+
218
+ data = @database[:items].first
219
+ assert_equal data[:name], "Name from block"
220
+ end
221
+
222
+ def test_column_assign_with_no_field
223
+ doc = {'type' => 'Item', 'name' => "Some Other Item", '_id' => '1234'}
224
+ @handler.document = doc
225
+ @row = CouchTap::Builders::Table.new @handler, :items do
226
+ column :name
227
+ end
228
+ @row.execute
229
+
230
+ data = @database[:items].first
231
+ assert_equal data[:name], doc['name']
232
+ end
233
+
234
+
235
+ protected
236
+
237
+ def create_database
238
+ database = Sequel.sqlite
239
+ database.create_table :items do
240
+ String :item_id
241
+ String :name
242
+ Integer :count
243
+ Float :price
244
+ Time :created_at
245
+ index :item_id, :unique => true
246
+ end
247
+ database
248
+ end
249
+
250
+ def create_many_to_many_items
251
+ @database.create_table :group_items do
252
+ String :group_id
253
+ String :item_id
254
+ index :group_id
255
+ end
256
+ end
257
+
258
+ end
259
+ end
@@ -0,0 +1,95 @@
1
+
2
+ require 'test_helper'
3
+
4
+ class ChangesTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ reset_test_db!
8
+ build_sample_config
9
+ end
10
+
11
+ def test_basic_init
12
+ @database = @changes.database
13
+ assert @changes.database, "Did not assign a database"
14
+ assert @changes.database.is_a?(Sequel::Database)
15
+ row = @database[:couch_sequence].first
16
+ assert row, "Did not create a couch_sequence table"
17
+ assert_equal row[:seq], 0, "Did not set a default sequence number"
18
+ assert_equal row[:name], TEST_DB_NAME, "Sequence name does not match"
19
+ end
20
+
21
+ def test_defining_document_handler
22
+ assert_equal @changes.handlers.length, 3
23
+ handler = @changes.handlers.first
24
+ assert handler.is_a?(CouchTap::DocumentHandler)
25
+ assert_equal handler.filter, :type => 'Foo'
26
+ end
27
+
28
+ def test_inserting_rows
29
+ row = {'seq' => 1, 'id' => '1234'}
30
+ doc = {'_id' => '1234', 'type' => 'Foo', 'name' => 'Some Document'}
31
+ @changes.expects(:fetch_document).with('1234').returns(doc)
32
+
33
+ handler = @changes.handlers.first
34
+ handler.expects(:delete).with(doc)
35
+ handler.expects(:insert).with(doc)
36
+
37
+ @changes.send(:process_row, row)
38
+
39
+ # Should update seq
40
+ assert_equal @changes.database[:couch_sequence].first[:seq], 1
41
+ end
42
+
43
+ def test_inserting_rows_with_mutiple_filters
44
+ row = {'seq' => 3, 'id' => '1234'}
45
+ doc = {'_id' => '1234', 'type' => 'Bar', 'special' => true, 'name' => 'Some Document'}
46
+ @changes.expects(:fetch_document).with('1234').returns(doc)
47
+
48
+ handler = @changes.handlers[0]
49
+ handler.expects(:insert).never
50
+ handler = @changes.handlers[1]
51
+ handler.expects(:delete)
52
+ handler.expects(:insert)
53
+ handler = @changes.handlers[2]
54
+ handler.expects(:delete)
55
+ handler.expects(:insert)
56
+
57
+ @changes.send(:process_row, row)
58
+ assert_equal @changes.database[:couch_sequence].first[:seq], 3
59
+ end
60
+
61
+ def test_deleting_rows
62
+ row = {'seq' => 9, 'id' => '1234', 'deleted' => true}
63
+
64
+ @changes.handlers.each do |handler|
65
+ handler.expects(:delete).with({'_id' => row['id']})
66
+ end
67
+
68
+ @changes.send(:process_row, row)
69
+
70
+ assert_equal @changes.database[:couch_sequence].first[:seq], 9
71
+ end
72
+
73
+ def test_returning_schema
74
+ schema = mock()
75
+ CouchTap::Schema.expects(:new).once.with(@changes.database, :items).returns(schema)
76
+ # Run twice to ensure cached
77
+ assert_equal @changes.schema(:items), schema
78
+ assert_equal @changes.schema(:items), schema
79
+ end
80
+
81
+ protected
82
+
83
+ def build_sample_config
84
+ @changes = CouchTap::Changes.new(TEST_DB_ROOT) do
85
+ database "sqlite:/"
86
+ document :type => 'Foo' do
87
+ end
88
+ document :type => 'Bar' do
89
+ end
90
+ document :type => 'Bar', :special => true do
91
+ end
92
+ end
93
+ end
94
+
95
+ end