molo 0.5.0 → 0.6.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.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- Molo (0.4.0)
4
+ molo (0.5.0)
5
5
  activerecord (~> 3.0.3)
6
6
  rake (~> 0.8)
7
7
 
@@ -28,6 +28,6 @@ PLATFORMS
28
28
  ruby
29
29
 
30
30
  DEPENDENCIES
31
- Molo!
32
31
  activerecord (~> 3.0.3)
32
+ molo!
33
33
  rake (~> 0.8)
data/Molo.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{molo}
8
- s.version = "0.5.0"
8
+ s.version = "0.6.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Joel Moss", "Todd Huss", "Michael Grosser"]
12
- s.date = %q{2010-12-13}
12
+ s.date = %q{2010-12-14}
13
13
  s.email = %q{joel@developwithstyle.com}
14
14
  s.extra_rdoc_files = [
15
15
  "README.markdown"
@@ -27,7 +27,19 @@ Gem::Specification.new do |s|
27
27
  "vendor/migration_helpers/MIT-LICENSE",
28
28
  "vendor/migration_helpers/README.markdown",
29
29
  "vendor/migration_helpers/init.rb",
30
- "vendor/migration_helpers/lib/migration_helper.rb"
30
+ "vendor/migration_helpers/lib/migration_helper.rb",
31
+ "vendor/yaml_db/init.rb",
32
+ "vendor/yaml_db/lib/csv_db.rb",
33
+ "vendor/yaml_db/lib/serialization_helper.rb",
34
+ "vendor/yaml_db/lib/yaml_db.rb",
35
+ "vendor/yaml_db/spec/base.rb",
36
+ "vendor/yaml_db/spec/serialization_helper_base_spec.rb",
37
+ "vendor/yaml_db/spec/serialization_helper_dump_spec.rb",
38
+ "vendor/yaml_db/spec/serialization_helper_load_spec.rb",
39
+ "vendor/yaml_db/spec/serialization_utils_spec.rb",
40
+ "vendor/yaml_db/spec/yaml_dump_spec.rb",
41
+ "vendor/yaml_db/spec/yaml_load_spec.rb",
42
+ "vendor/yaml_db/spec/yaml_utils_spec.rb"
31
43
  ]
32
44
  s.homepage = %q{http://codaset.com/joelmoss/molo}
33
45
  s.rdoc_options = ["--charset=UTF-8"]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.6.0
data/lib/tasks/molo.rb CHANGED
@@ -33,10 +33,11 @@ class MigratorTasks < ::Rake::TaskLib
33
33
  namespace :db do
34
34
  task :ar_init do
35
35
  require 'active_record'
36
- ENV[@env] ||= @default_env
37
-
38
36
  require 'erb'
37
+ require 'yaml_db'
39
38
 
39
+ ENV[@env] ||= @default_env
40
+
40
41
  if @config.is_a?(Hash)
41
42
  ActiveRecord::Base.configurations = @config
42
43
  else
@@ -171,7 +172,7 @@ class MigratorTasks < ::Rake::TaskLib
171
172
  puts "Current version: #{ActiveRecord::Migrator.current_version}"
172
173
  end
173
174
 
174
- desc "Raises an error if there are pending migrations"
175
+ # desc "Raises an error if there are pending migrations"
175
176
  task :abort_if_pending_migrations => :ar_init do
176
177
  @migrations.each do |path|
177
178
  pending_migrations = ActiveRecord::Migrator.new(:up, path).pending_migrations
@@ -204,6 +205,50 @@ class MigratorTasks < ::Rake::TaskLib
204
205
  end
205
206
  end
206
207
 
208
+ desc "Dump schema and data to db/schema.rb and db/data.yml"
209
+ task(:dump => [ "db:schema:dump", "db:data:dump" ])
210
+
211
+ desc "Load schema and data from db/schema.rb and db/data.yml"
212
+ task(:load => [ "db:schema:load", "db:data:load" ])
213
+
214
+ namespace :data do
215
+ def db_dump_data_file (extension = "yml")
216
+ "#{dump_dir}/data.#{extension}"
217
+ end
218
+
219
+ def dump_dir(dir = "")
220
+ "#{base}/db#{dir}"
221
+ end
222
+
223
+ desc "Dump contents of database to db/data.extension (defaults to yaml)"
224
+ task :dump => :ar_init do
225
+ format_class = ENV['class'] || "YamlDb::Helper"
226
+ helper = format_class.constantize
227
+ SerializationHelper::Base.new(helper).dump db_dump_data_file helper.extension
228
+ end
229
+
230
+ desc "Dump contents of database to db/data/tablename.extension (defaults to yaml)"
231
+ task :dump_dir => :ar_init do
232
+ format_class = ENV['class'] || "YamlDb::Helper"
233
+ dir = ENV['dir'] || "data"
234
+ SerializationHelper::Base.new(format_class.constantize).dump_to_dir dump_dir("/#{dir}")
235
+ end
236
+
237
+ desc "Load contents of db/data.extension (defaults to yaml) into database"
238
+ task :load => :ar_init do
239
+ format_class = ENV['class'] || "YamlDb::Helper"
240
+ helper = format_class.constantize
241
+ SerializationHelper::Base.new(helper).load(db_dump_data_file helper.extension)
242
+ end
243
+
244
+ desc "Load contents of db/data/* into database"
245
+ task :load_dir => :ar_init do
246
+ dir = ENV['dir'] || "data"
247
+ format_class = ENV['class'] || "YamlDb::Helper"
248
+ SerializationHelper::Base.new(format_class.constantize).load_from_dir dump_dir("/#{dir}")
249
+ end
250
+ end
251
+
207
252
  namespace :test do
208
253
  desc "Recreate the test database from the current schema.rb"
209
254
  task :load => ['db:ar_init', 'db:test:purge'] do
@@ -0,0 +1 @@
1
+ require "yaml_db"
@@ -0,0 +1,78 @@
1
+ #require 'FasterCSV'
2
+ module CsvDb
3
+ module Helper
4
+ def self.loader
5
+ Load
6
+ end
7
+
8
+ def self.dumper
9
+ Dump
10
+ end
11
+
12
+ def self.extension
13
+ "csv"
14
+ end
15
+ end
16
+
17
+ class Load < SerializationHelper::Load
18
+ def self.load_documents(io, truncate = true)
19
+ tables = {}
20
+ curr_table = nil
21
+ io.each do |line|
22
+ if /BEGIN_CSV_TABLE_DECLARATION(.+)END_CSV_TABLE_DECLARATION/ =~ line
23
+ curr_table = $1
24
+ tables[curr_table] = {}
25
+ else
26
+ if tables[curr_table]["columns"]
27
+ tables[curr_table]["records"] << FasterCSV.parse(line)[0]
28
+ else
29
+ tables[curr_table]["columns"] = FasterCSV.parse(line)[0]
30
+ tables[curr_table]["records"] = []
31
+ end
32
+ end
33
+ end
34
+
35
+ tables.each_pair do |table_name, contents|
36
+ load_table(table_name, contents, truncate)
37
+ end
38
+ end
39
+ end
40
+
41
+ class Dump < SerializationHelper::Dump
42
+
43
+ def self.before_table(io,table)
44
+ io.write "BEGIN_CSV_TABLE_DECLARATION#{table}END_CSV_TABLE_DECLARATION\n"
45
+ end
46
+
47
+ def self.dump(io)
48
+ tables.each do |table|
49
+ before_table(io, table)
50
+ dump_table(io, table)
51
+ after_table(io, table)
52
+ end
53
+ end
54
+
55
+ def self.after_table(io,table)
56
+ io.write ""
57
+ end
58
+
59
+ def self.dump_table_columns(io, table)
60
+ io.write(table_column_names(table).to_csv)
61
+ end
62
+
63
+ def self.dump_table_records(io, table)
64
+
65
+ column_names = table_column_names(table)
66
+
67
+ each_table_page(table) do |records|
68
+ rows = SerializationHelper::Utils.unhash_records(records, column_names)
69
+ records.each do |record|
70
+ io.write(record.to_csv)
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+
78
+ end
@@ -0,0 +1,195 @@
1
+ module SerializationHelper
2
+
3
+ class Base
4
+ attr_reader :extension
5
+
6
+ def initialize(helper)
7
+ @dumper = helper.dumper
8
+ @loader = helper.loader
9
+ @extension = helper.extension
10
+ end
11
+
12
+ def dump(filename)
13
+ disable_logger
14
+ @dumper.dump(File.new(filename, "w"))
15
+ reenable_logger
16
+ end
17
+
18
+ def dump_to_dir(dirname)
19
+ Dir.mkdir(dirname)
20
+ tables = @dumper.tables
21
+ tables.each do |table|
22
+ io = File.new "#{dirname}/#{table}.#{@extension}", "w"
23
+ @dumper.before_table(io, table)
24
+ @dumper.dump_table io, table
25
+ @dumper.after_table(io, table)
26
+ end
27
+ end
28
+
29
+ def load(filename, truncate = true)
30
+ disable_logger
31
+ @loader.load(File.new(filename, "r"), truncate)
32
+ reenable_logger
33
+ end
34
+
35
+ def load_from_dir(dirname, truncate = true)
36
+ Dir.entries(dirname).each do |filename|
37
+ if filename =~ /^[.]/
38
+ next
39
+ end
40
+ @loader.load(File.new("#{dirname}/#{filename}", "r"), truncate)
41
+ end
42
+ end
43
+
44
+ def disable_logger
45
+ @@old_logger = ActiveRecord::Base.logger
46
+ ActiveRecord::Base.logger = nil
47
+ end
48
+
49
+ def reenable_logger
50
+ ActiveRecord::Base.logger = @@old_logger
51
+ end
52
+ end
53
+
54
+ class Load
55
+ def self.load(io, truncate = true)
56
+ ActiveRecord::Base.connection.transaction do
57
+ load_documents(io, truncate)
58
+ end
59
+ end
60
+
61
+ def self.truncate_table(table)
62
+ begin
63
+ ActiveRecord::Base.connection.execute("TRUNCATE #{SerializationHelper::Utils.quote_table(table)}")
64
+ rescue Exception
65
+ ActiveRecord::Base.connection.execute("DELETE FROM #{SerializationHelper::Utils.quote_table(table)}")
66
+ end
67
+ end
68
+
69
+ def self.load_table(table, data, truncate = true)
70
+ column_names = data['columns']
71
+ if truncate
72
+ truncate_table(table)
73
+ end
74
+ load_records(table, column_names, data['records'])
75
+ reset_pk_sequence!(table)
76
+ end
77
+
78
+ def self.load_records(table, column_names, records)
79
+ if column_names.nil?
80
+ return
81
+ end
82
+ columns = column_names.map{|cn| ActiveRecord::Base.connection.columns(table).detect{|c| c.name == cn}}
83
+ quoted_column_names = column_names.map { |column| ActiveRecord::Base.connection.quote_column_name(column) }.join(',')
84
+ quoted_table_name = SerializationHelper::Utils.quote_table(table)
85
+ records.each do |record|
86
+ quoted_values = record.zip(columns).map{|c| ActiveRecord::Base.connection.quote(c.first, c.last)}.join(',')
87
+ ActiveRecord::Base.connection.execute("INSERT INTO #{quoted_table_name} (#{quoted_column_names}) VALUES (#{quoted_values})")
88
+ end
89
+ end
90
+
91
+ def self.reset_pk_sequence!(table_name)
92
+ if ActiveRecord::Base.connection.respond_to?(:reset_pk_sequence!)
93
+ ActiveRecord::Base.connection.reset_pk_sequence!(table_name)
94
+ end
95
+ end
96
+
97
+
98
+ end
99
+
100
+ module Utils
101
+
102
+ def self.unhash(hash, keys)
103
+ keys.map { |key| hash[key] }
104
+ end
105
+
106
+ def self.unhash_records(records, keys)
107
+ records.each_with_index do |record, index|
108
+ records[index] = unhash(record, keys)
109
+ end
110
+
111
+ records
112
+ end
113
+
114
+ def self.convert_booleans(records, columns)
115
+ records.each do |record|
116
+ columns.each do |column|
117
+ next if is_boolean(record[column])
118
+ record[column] = (record[column] == 't' or record[column] == '1')
119
+ end
120
+ end
121
+ records
122
+ end
123
+
124
+ def self.boolean_columns(table)
125
+ columns = ActiveRecord::Base.connection.columns(table).reject { |c| silence_warnings { c.type != :boolean } }
126
+ columns.map { |c| c.name }
127
+ end
128
+
129
+ def self.is_boolean(value)
130
+ value.kind_of?(TrueClass) or value.kind_of?(FalseClass)
131
+ end
132
+
133
+ def self.quote_table(table)
134
+ ActiveRecord::Base.connection.quote_table_name(table)
135
+ end
136
+
137
+ end
138
+
139
+ class Dump
140
+ def self.before_table(io, table)
141
+
142
+ end
143
+
144
+ def self.dump(io)
145
+ tables.each do |table|
146
+ before_table(io, table)
147
+ dump_table(io, table)
148
+ after_table(io, table)
149
+ end
150
+ end
151
+
152
+ def self.after_table(io, table)
153
+
154
+ end
155
+
156
+ def self.tables
157
+ ActiveRecord::Base.connection.tables.reject { |table| ['schema_info', 'schema_migrations'].include?(table) }
158
+ end
159
+
160
+ def self.dump_table(io, table)
161
+ return if table_record_count(table).zero?
162
+
163
+ dump_table_columns(io, table)
164
+ dump_table_records(io, table)
165
+ end
166
+
167
+ def self.table_column_names(table)
168
+ ActiveRecord::Base.connection.columns(table).map { |c| c.name }
169
+ end
170
+
171
+
172
+ def self.each_table_page(table, records_per_page=1000)
173
+ total_count = table_record_count(table)
174
+ pages = (total_count.to_f / records_per_page).ceil - 1
175
+ id = table_column_names(table).first
176
+ boolean_columns = SerializationHelper::Utils.boolean_columns(table)
177
+ quoted_table_name = SerializationHelper::Utils.quote_table(table)
178
+
179
+ (0..pages).to_a.each do |page|
180
+ sql = ActiveRecord::Base.connection.add_limit_offset!("SELECT * FROM #{quoted_table_name} ORDER BY #{id}",
181
+ :limit => records_per_page, :offset => records_per_page * page
182
+ )
183
+ records = ActiveRecord::Base.connection.select_all(sql)
184
+ records = SerializationHelper::Utils.convert_booleans(records, boolean_columns)
185
+ yield records
186
+ end
187
+ end
188
+
189
+ def self.table_record_count(table)
190
+ ActiveRecord::Base.connection.select_one("SELECT COUNT(*) FROM #{SerializationHelper::Utils.quote_table(table)}").values.first.to_i
191
+ end
192
+
193
+ end
194
+
195
+ end
@@ -0,0 +1,66 @@
1
+ require 'yaml'
2
+ require 'serialization_helper'
3
+ require 'active_support/core_ext/kernel/reporting'
4
+
5
+ module YamlDb
6
+ module Helper
7
+ def self.loader
8
+ YamlDb::Load
9
+ end
10
+
11
+ def self.dumper
12
+ YamlDb::Dump
13
+ end
14
+
15
+ def self.extension
16
+ "yml"
17
+ end
18
+ end
19
+
20
+
21
+ module Utils
22
+ def self.chunk_records(records)
23
+ yaml = [ records ].to_yaml
24
+ yaml.sub!("--- \n", "")
25
+ yaml.sub!('- - -', ' - -')
26
+ yaml
27
+ end
28
+
29
+ end
30
+
31
+ class Dump < SerializationHelper::Dump
32
+
33
+ def self.dump_table_columns(io, table)
34
+ io.write("\n")
35
+ io.write({ table => { 'columns' => table_column_names(table) } }.to_yaml)
36
+ end
37
+
38
+ def self.dump_table_records(io, table)
39
+ table_record_header(io)
40
+
41
+ column_names = table_column_names(table)
42
+
43
+ each_table_page(table) do |records|
44
+ rows = SerializationHelper::Utils.unhash_records(records, column_names)
45
+ io.write(YamlDb::Utils.chunk_records(records))
46
+ end
47
+ end
48
+
49
+ def self.table_record_header(io)
50
+ io.write(" records: \n")
51
+ end
52
+
53
+ end
54
+
55
+ class Load < SerializationHelper::Load
56
+ def self.load_documents(io, truncate = true)
57
+ YAML.load_documents(io) do |ydoc|
58
+ ydoc.keys.each do |table_name|
59
+ next if ydoc[table_name].nil?
60
+ load_table(table_name, ydoc[table_name], truncate)
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'spec'
4
+ require 'spec/autorun'
5
+ require 'yaml_db'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe SerializationHelper::Base do
4
+
5
+ before do
6
+ @io = StringIO.new
7
+ silence_warnings { ActiveRecord::Base = mock('ActiveRecord::Base', :null_object => true) }
8
+ ActiveRecord::Base.connection = mock('connection')
9
+ ActiveRecord::Base.connection.stub!(:tables).and_return([ 'mytable', 'schema_info', 'schema_migrations' ])
10
+ end
11
+
12
+ def stub_helper!
13
+ @helper = mock("MyHelper")
14
+ @dumper = mock("MyDumper");
15
+ @loader = mock("MyLoader");
16
+ @helper.stub!(:dumper).and_return(@dumper)
17
+ @helper.stub!(:loader).and_return(@loader)
18
+ @helper.stub!(:extension).and_return("yml")
19
+ @dumper.stub!(:tables).and_return([ActiveRecord::Base.connection.tables[0]])
20
+ @dumper.stub!(:before_table).and_return(nil)
21
+ @dumper.stub!(:after_table).and_return(nil)
22
+ end
23
+
24
+ context "for multi-file dumps" do
25
+ before do
26
+ File.should_receive(:new).once.with("dir_name/mytable.yml", "w").and_return(@io)
27
+ Dir.should_receive(:mkdir).once.with("dir_name")
28
+ stub_helper!
29
+ @dumper.should_receive(:dump_table).once.with(@io, "mytable")
30
+ end
31
+
32
+ it "should create the number of files that there are tables" do
33
+ SerializationHelper::Base.new(@helper).dump_to_dir "dir_name"
34
+ end
35
+
36
+ end
37
+
38
+ context "for multi-file loads" do
39
+
40
+ before do
41
+ stub_helper!
42
+ @loader.should_receive(:load).once.with(@io, true)
43
+ File.should_receive(:new).once.with("dir_name/mytable.yml", "r").and_return(@io)
44
+ Dir.stub!(:entries).and_return(["mytable.yml"])
45
+ end
46
+
47
+ it "should insert into then umber of tables that there are files" do
48
+ SerializationHelper::Base.new(@helper).load_from_dir "dir_name"
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,65 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe SerializationHelper::Dump do
4
+
5
+ before do
6
+ silence_warnings { ActiveRecord::Base = mock('ActiveRecord::Base', :null_object => true) }
7
+ ActiveRecord::Base.connection = mock('connection')
8
+ ActiveRecord::Base.connection.stub!(:tables).and_return([ 'mytable', 'schema_info', 'schema_migrations' ])
9
+ ActiveRecord::Base.connection.stub!(:columns).with('mytable').and_return([ mock('a',:name => 'a'), mock('b', :name => 'b') ])
10
+ ActiveRecord::Base.connection.stub!(:select_one).and_return({"count"=>"2"})
11
+ ActiveRecord::Base.connection.stub!(:select_all).and_return([ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ])
12
+ SerializationHelper::Utils.stub!(:quote_table).with('mytable').and_return('mytable')
13
+ end
14
+
15
+ before(:each) do
16
+ File.stub!(:new).with('dump.yml', 'w').and_return(StringIO.new)
17
+ @io = StringIO.new
18
+ end
19
+
20
+ it "should return a list of column names" do
21
+ SerializationHelper::Dump.table_column_names('mytable').should == [ 'a', 'b' ]
22
+ end
23
+
24
+ it "should return a list of tables without the rails schema table" do
25
+ SerializationHelper::Dump.tables.should == ['mytable']
26
+ end
27
+
28
+ it "should return the total number of records in a table" do
29
+ SerializationHelper::Dump.table_record_count('mytable').should == 2
30
+ end
31
+
32
+ it "should return all records from the database and return them when there is only 1 page" do
33
+ SerializationHelper::Dump.each_table_page('mytable') do |records|
34
+ records.should == [ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ]
35
+ end
36
+ end
37
+
38
+ it "should paginate records from the database and return them" do
39
+ ActiveRecord::Base.connection.stub!(:select_all).and_return([ { 'a' => 1, 'b' => 2 } ], [ { 'a' => 3, 'b' => 4 } ])
40
+
41
+ records = [ ]
42
+ SerializationHelper::Dump.each_table_page('mytable', 1) do |page|
43
+ page.size.should == 1
44
+ records.concat(page)
45
+ end
46
+
47
+ records.should == [ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ]
48
+ end
49
+
50
+ it "should dump a table's contents to yaml" do
51
+ SerializationHelper::Dump.should_receive(:dump_table_columns)
52
+ SerializationHelper::Dump.should_receive(:dump_table_records)
53
+ SerializationHelper::Dump.dump_table(@io, 'mytable')
54
+ end
55
+
56
+ it "should not dump a table's contents when the record count is zero" do
57
+ SerializationHelper::Dump.stub!(:table_record_count).with('mytable').and_return(0)
58
+ SerializationHelper::Dump.should_not_receive(:dump_table_columns)
59
+ SerializationHelper::Dump.should_not_receive(:dump_table_records)
60
+ SerializationHelper::Dump.dump_table(@io, 'mytable')
61
+ end
62
+
63
+
64
+
65
+ end
@@ -0,0 +1,77 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe SerializationHelper::Load do
4
+ before do
5
+ SerializationHelper::Utils.stub!(:quote_table).with('mytable').and_return('mytable')
6
+
7
+ silence_warnings { ActiveRecord::Base = mock('ActiveRecord::Base', :null_object => true) }
8
+ ActiveRecord::Base.connection = mock('connection')
9
+ ActiveRecord::Base.connection.stub!(:transaction).and_yield
10
+ @io = StringIO.new
11
+ end
12
+
13
+ it "should truncate the table" do
14
+ ActiveRecord::Base.connection.stub!(:execute).with("TRUNCATE mytable").and_return(true)
15
+ ActiveRecord::Base.connection.should_not_receive(:execute).with("DELETE FROM mytable")
16
+ SerializationHelper::Load.truncate_table('mytable')
17
+ end
18
+
19
+ it "should delete the table if truncate throws an exception" do
20
+ ActiveRecord::Base.connection.should_receive(:execute).with("TRUNCATE mytable").and_raise()
21
+ ActiveRecord::Base.connection.should_receive(:execute).with("DELETE FROM mytable").and_return(true)
22
+ SerializationHelper::Load.truncate_table('mytable')
23
+ end
24
+
25
+
26
+ it "should call reset pk sequence if the connection adapter is postgres" do
27
+ ActiveRecord::Base.connection.should_receive(:respond_to?).with(:reset_pk_sequence!).and_return(true)
28
+ ActiveRecord::Base.connection.should_receive(:reset_pk_sequence!).with('mytable')
29
+ SerializationHelper::Load.reset_pk_sequence!('mytable')
30
+ end
31
+
32
+ it "should not call reset pk sequence for other adapters" do
33
+ ActiveRecord::Base.connection.should_receive(:respond_to?).with(:reset_pk_sequence!).and_return(false)
34
+ ActiveRecord::Base.connection.should_not_receive(:reset_pk_sequence!)
35
+ SerializationHelper::Load.reset_pk_sequence!('mytable')
36
+ end
37
+
38
+ it "should insert records into a table" do
39
+ mca = mock('a',:name => 'a')
40
+ mcb = mock('b', :name => 'b')
41
+ ActiveRecord::Base.connection.stub!(:columns).with('mytable').and_return([mca , mcb ])
42
+ ActiveRecord::Base.connection.stub!(:quote_column_name).with('a').and_return('a')
43
+ ActiveRecord::Base.connection.stub!(:quote_column_name).with('b').and_return('b')
44
+ ActiveRecord::Base.connection.stub!(:quote).with(1, mca).and_return("'1'")
45
+ ActiveRecord::Base.connection.stub!(:quote).with(2, mcb).and_return("'2'")
46
+ ActiveRecord::Base.connection.stub!(:quote).with(3, mca).and_return("'3'")
47
+ ActiveRecord::Base.connection.stub!(:quote).with(4, mcb).and_return("'4'")
48
+ ActiveRecord::Base.connection.should_receive(:execute).with("INSERT INTO mytable (a,b) VALUES ('1','2')")
49
+ ActiveRecord::Base.connection.should_receive(:execute).with("INSERT INTO mytable (a,b) VALUES ('3','4')")
50
+
51
+ SerializationHelper::Load.load_records('mytable', ['a', 'b'], [[1, 2], [3, 4]])
52
+ end
53
+
54
+ it "should quote column names that correspond to sql keywords" do
55
+ mca = mock('a',:name => 'a')
56
+ mccount = mock('count', :name => 'count')
57
+ ActiveRecord::Base.connection.stub!(:columns).with('mytable').and_return([mca , mccount ])
58
+ ActiveRecord::Base.connection.stub!(:quote_column_name).with('a').and_return('a')
59
+ ActiveRecord::Base.connection.stub!(:quote_column_name).with('count').and_return('"count"')
60
+ ActiveRecord::Base.connection.stub!(:quote).with(1, mca).and_return("'1'")
61
+ ActiveRecord::Base.connection.stub!(:quote).with(2, mccount).and_return("'2'")
62
+ ActiveRecord::Base.connection.stub!(:quote).with(3, mca).and_return("'3'")
63
+ ActiveRecord::Base.connection.stub!(:quote).with(4, mccount).and_return("'4'")
64
+ ActiveRecord::Base.connection.should_receive(:execute).with("INSERT INTO mytable (a,\"count\") VALUES ('1','2')")
65
+ ActiveRecord::Base.connection.should_receive(:execute).with("INSERT INTO mytable (a,\"count\") VALUES ('3','4')")
66
+
67
+ SerializationHelper::Load.load_records('mytable', ['a', 'count'], [[1, 2], [3, 4]])
68
+ end
69
+
70
+ it "should truncate the table and then load the records into the table" do
71
+ SerializationHelper::Load.should_receive(:truncate_table).with('mytable')
72
+ SerializationHelper::Load.should_receive(:load_records).with('mytable', ['a', 'b'], [[1, 2], [3, 4]])
73
+ SerializationHelper::Load.should_receive(:reset_pk_sequence!).with('mytable')
74
+
75
+ SerializationHelper::Load.load_table('mytable', { 'columns' => [ 'a', 'b' ], 'records' => [[1, 2], [3, 4]] })
76
+ end
77
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe SerializationHelper::Utils, " convert records utility method" do
4
+ before do
5
+ silence_warnings { ActiveRecord::Base = mock('ActiveRecord::Base', :null_object => true) }
6
+ ActiveRecord::Base.connection = mock('connection')
7
+ end
8
+
9
+ it "returns an array of hash values using an array of ordered keys" do
10
+ SerializationHelper::Utils.unhash({ 'a' => 1, 'b' => 2 }, [ 'b', 'a' ]).should == [ 2, 1 ]
11
+ end
12
+
13
+ it "should unhash each hash an array using an array of ordered keys" do
14
+ SerializationHelper::Utils.unhash_records([ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ], [ 'b', 'a' ]).should == [ [ 2, 1 ], [ 4, 3 ] ]
15
+ end
16
+
17
+ it "should return true if it is a boolean type" do
18
+ SerializationHelper::Utils.is_boolean(true).should == true
19
+ SerializationHelper::Utils.is_boolean('true').should_not == true
20
+ end
21
+
22
+ it "should return an array of boolean columns" do
23
+ ActiveRecord::Base.connection.stub!(:columns).with('mytable').and_return([ mock('a',:name => 'a',:type => :string), mock('b', :name => 'b',:type => :boolean) ])
24
+ SerializationHelper::Utils.boolean_columns('mytable').should == ['b']
25
+ end
26
+
27
+ it "should quote the table name" do
28
+ ActiveRecord::Base.connection.should_receive(:quote_table_name).with('values').and_return('`values`')
29
+ SerializationHelper::Utils.quote_table('values').should == '`values`'
30
+ end
31
+ end
@@ -0,0 +1,55 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe YamlDb::Dump do
4
+
5
+ before do
6
+ silence_warnings { ActiveRecord::Base = mock('ActiveRecord::Base', :null_object => true) }
7
+ ActiveRecord::Base.connection = mock('connection')
8
+ ActiveRecord::Base.connection.stub!(:tables).and_return([ 'mytable', 'schema_info', 'schema_migrations' ])
9
+ ActiveRecord::Base.connection.stub!(:columns).with('mytable').and_return([ mock('a',:name => 'a'), mock('b', :name => 'b') ])
10
+ ActiveRecord::Base.connection.stub!(:select_one).and_return({"count"=>"2"})
11
+ ActiveRecord::Base.connection.stub!(:select_all).and_return([ { 'a' => 1, 'b' => 2 }, { 'a' => 3, 'b' => 4 } ])
12
+ YamlDb::Utils.stub!(:quote_table).with('mytable').and_return('mytable')
13
+ end
14
+
15
+ before(:each) do
16
+ File.stub!(:new).with('dump.yml', 'w').and_return(StringIO.new)
17
+ @io = StringIO.new
18
+ end
19
+
20
+ it "should return a formatted string" do
21
+ YamlDb::Dump.table_record_header(@io)
22
+ @io.rewind
23
+ @io.read.should == " records: \n"
24
+ end
25
+
26
+
27
+ it "should return a yaml string that contains a table header and column names" do
28
+ YamlDb::Dump.stub!(:table_column_names).with('mytable').and_return([ 'a', 'b' ])
29
+ YamlDb::Dump.dump_table_columns(@io, 'mytable')
30
+ @io.rewind
31
+ @io.read.should == <<EOYAML
32
+
33
+ ---
34
+ mytable:
35
+ columns:
36
+ - a
37
+ - b
38
+ EOYAML
39
+ end
40
+
41
+ it "should return dump the records for a table in yaml to a given io stream" do
42
+ YamlDb::Dump.dump_table_records(@io, 'mytable')
43
+ @io.rewind
44
+ @io.read.should == <<EOYAML
45
+ records:
46
+ - - 1
47
+ - 2
48
+ - - 3
49
+ - 4
50
+ EOYAML
51
+ end
52
+
53
+
54
+
55
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+ require 'active_support/core_ext/kernel/debugger'
3
+
4
+ describe YamlDb::Load do
5
+ before do
6
+ SerializationHelper::Utils.stub!(:quote_table).with('mytable').and_return('mytable')
7
+
8
+ silence_warnings { ActiveRecord::Base = mock('ActiveRecord::Base', :null_object => true) }
9
+ ActiveRecord::Base.connection = mock('connection')
10
+ ActiveRecord::Base.connection.stub!(:transaction).and_yield
11
+ end
12
+
13
+ before(:each) do
14
+ @io = StringIO.new
15
+ end
16
+
17
+
18
+ it "should call load structure for each document in the file" do
19
+ YAML.should_receive(:load_documents).with(@io).and_yield({ 'mytable' => {
20
+ 'columns' => [ 'a', 'b' ],
21
+ 'records' => [[1, 2], [3, 4]]
22
+ } } )
23
+ YamlDb::Load.should_receive(:load_table).with('mytable', { 'columns' => [ 'a', 'b' ], 'records' => [[1, 2], [3, 4]] },true)
24
+ YamlDb::Load.load(@io)
25
+ end
26
+
27
+ it "should not call load structure when the document in the file contains no records" do
28
+ YAML.should_receive(:load_documents).with(@io).and_yield({ 'mytable' => nil })
29
+ YamlDb::Load.should_not_receive(:load_table)
30
+ YamlDb::Load.load(@io)
31
+ end
32
+
33
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe YamlDb::Utils, " convert records utility method" do
4
+
5
+ it "turns an array with one record into a yaml chunk" do
6
+ YamlDb::Utils.chunk_records([ %w(a b) ]).should == <<EOYAML
7
+ - - a
8
+ - b
9
+ EOYAML
10
+ end
11
+
12
+ it "turns an array with two records into a yaml chunk" do
13
+ YamlDb::Utils.chunk_records([ %w(a b), %w(x y) ]).should == <<EOYAML
14
+ - - a
15
+ - b
16
+ - - x
17
+ - y
18
+ EOYAML
19
+ end
20
+
21
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: molo
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 7
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 5
8
+ - 6
9
9
  - 0
10
- version: 0.5.0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Joel Moss
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2010-12-13 00:00:00 +00:00
20
+ date: 2010-12-14 00:00:00 +00:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -73,6 +73,18 @@ files:
73
73
  - vendor/migration_helpers/README.markdown
74
74
  - vendor/migration_helpers/init.rb
75
75
  - vendor/migration_helpers/lib/migration_helper.rb
76
+ - vendor/yaml_db/init.rb
77
+ - vendor/yaml_db/lib/csv_db.rb
78
+ - vendor/yaml_db/lib/serialization_helper.rb
79
+ - vendor/yaml_db/lib/yaml_db.rb
80
+ - vendor/yaml_db/spec/base.rb
81
+ - vendor/yaml_db/spec/serialization_helper_base_spec.rb
82
+ - vendor/yaml_db/spec/serialization_helper_dump_spec.rb
83
+ - vendor/yaml_db/spec/serialization_helper_load_spec.rb
84
+ - vendor/yaml_db/spec/serialization_utils_spec.rb
85
+ - vendor/yaml_db/spec/yaml_dump_spec.rb
86
+ - vendor/yaml_db/spec/yaml_load_spec.rb
87
+ - vendor/yaml_db/spec/yaml_utils_spec.rb
76
88
  has_rdoc: true
77
89
  homepage: http://codaset.com/joelmoss/molo
78
90
  licenses: []