couch_tap 0.0.2

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.
@@ -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