squealer 1.0.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/.gitignore +1 -0
- data/.watchr +27 -0
- data/README.md +13 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/lib/example_squeal.rb +38 -0
- data/lib/squealer/database.rb +26 -0
- data/lib/squealer/hash.rb +6 -0
- data/lib/squealer/object.rb +33 -0
- data/lib/squealer/target.rb +106 -0
- data/lib/squealer/time.rb +5 -0
- data/lib/squealer.rb +6 -0
- data/lib/tasks/jeweler.rake +15 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/squealer/database_spec.rb +41 -0
- data/spec/squealer/hash_spec.rb +28 -0
- data/spec/squealer/object_spec.rb +113 -0
- data/spec/squealer/target_spec.rb +135 -0
- data/spec/squealer/time_spec.rb +10 -0
- data/squealer.gemspec +71 -0
- metadata +115 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg/
|
data/.watchr
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# ~/.vim/ftdetect/watchr.vim
|
2
|
+
#
|
3
|
+
# This should have only the following line in it:
|
4
|
+
#
|
5
|
+
# autocmd BufNewFile,BufRead *.watchr setf ruby
|
6
|
+
#
|
7
|
+
# This will enable vim to recognize this file as ruby code should you wish to
|
8
|
+
# edit it.
|
9
|
+
def run(cmd)
|
10
|
+
puts cmd
|
11
|
+
system cmd
|
12
|
+
end
|
13
|
+
|
14
|
+
def spec(file)
|
15
|
+
run "spec -O spec/spec.opts #{file}"
|
16
|
+
end
|
17
|
+
|
18
|
+
watch("spec/.*/*_spec\.rb") do |match|
|
19
|
+
p match[0]
|
20
|
+
spec(match[0])
|
21
|
+
end
|
22
|
+
|
23
|
+
watch("lib/(.*/.*)\.rb") do |match|
|
24
|
+
p match[1]
|
25
|
+
spec("spec/#{match[1]}_spec.rb")
|
26
|
+
end
|
27
|
+
|
data/README.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Squealer
|
2
|
+
|
3
|
+
For now, this is specifically for MongoDB exporting to mySQL with the assumption that the data will be heavily denormalized.
|
4
|
+
|
5
|
+
The target SQL database must have no foreign keys.
|
6
|
+
|
7
|
+
The target SQL database must use a primary key of char(16) with value of the MongoDB id.
|
8
|
+
|
9
|
+
It is assumed no indexes are present in the target database table.
|
10
|
+
|
11
|
+
The target row is inserted, or updated if present. We are using MySQL INSERT ... UPDATE ON DUPLICATE KEY extended syntax to achieve this for now. This allows an event-driven update of exported data as well as a bulk batch process.
|
12
|
+
|
13
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
|
8
|
+
task :default => [:spec]
|
9
|
+
Rake::Task[:default].clear
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gemspec|
|
14
|
+
gemspec.name = "squealer"
|
15
|
+
gemspec.summary = "Document-oriented to Relational database exporter"
|
16
|
+
gemspec.description = "Exports mongodb to mysql. More later."
|
17
|
+
gemspec.email = "joshua.graham@grahamis.com"
|
18
|
+
gemspec.homepage = "http://github.com/delitescere/squealer/"
|
19
|
+
gemspec.authors = ["Josh Graham", "Durran Jordan"]
|
20
|
+
gemspec.add_dependency('mysql', '>= 2.8.1')
|
21
|
+
gemspec.add_dependency('mongo', '>= 0.18.3')
|
22
|
+
end
|
23
|
+
Jeweler::GemcutterTasks.new
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
26
|
+
end
|
27
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'squealer'
|
2
|
+
|
3
|
+
import('localhost', 27017, 'development')
|
4
|
+
export('localhost', 'root', '', 'reporting_export')
|
5
|
+
|
6
|
+
import.collection("users").find({}).each do |user|
|
7
|
+
target(:user, user._id) do # insert or update on user where id is primary key column name
|
8
|
+
assign(:name) { user.first_name + " " + user.last_name.upcase }
|
9
|
+
assign(:dob) { user.dob }
|
10
|
+
|
11
|
+
user.activities.each do |activity|
|
12
|
+
target(:activity, activity._id) do
|
13
|
+
assign(:user_id) { user._id }
|
14
|
+
assign(:name) { activity.name }
|
15
|
+
end
|
16
|
+
|
17
|
+
activity.tasks.each do |task|
|
18
|
+
target(:task, task._id) do
|
19
|
+
assign(:user_id) { user._id }
|
20
|
+
assign(:activity_id) { activity._id }
|
21
|
+
assign(:date) { task.date }
|
22
|
+
end
|
23
|
+
end #activity.tasks
|
24
|
+
end #user.activities
|
25
|
+
end
|
26
|
+
end #collection("users")
|
27
|
+
|
28
|
+
import.collection("organization").find({}).each do |organization|
|
29
|
+
if organization.disabled
|
30
|
+
import.collection("users").find({ :organization_id => organization.id }) do |user|
|
31
|
+
target(:user, user.id) do
|
32
|
+
assign(:disabled) { true }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
# something else
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'mysql'
|
2
|
+
require 'mongo'
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
module Squealer
|
6
|
+
class Database
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
def import_from(host, port, name)
|
10
|
+
@import_dbc = Mongo::Connection.new(host, port, :slave_ok => true).db(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def export_to(host, username, password, name)
|
14
|
+
@export_dbc = Mysql.connect(host, username, password, name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def import
|
18
|
+
@import_dbc
|
19
|
+
end
|
20
|
+
|
21
|
+
def export
|
22
|
+
@export_dbc
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
def target(table_name, row_id, &block)
|
4
|
+
Squealer::Target.new(Squealer::Database.instance.export, table_name, row_id, &block)
|
5
|
+
end
|
6
|
+
|
7
|
+
def assign(column_name, &block)
|
8
|
+
Squealer::Target.current.assign(column_name, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def import(*args)
|
12
|
+
if args.length > 0
|
13
|
+
Squealer::Database.instance.import_from(*args)
|
14
|
+
else
|
15
|
+
Squealer::Database.instance.import
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def export(*args)
|
20
|
+
if args.length > 0
|
21
|
+
Squealer::Database.instance.export_to(*args)
|
22
|
+
else
|
23
|
+
Squealer::Database.instance.export
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
class NilClass
|
30
|
+
def each
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
module Squealer
|
5
|
+
class Target
|
6
|
+
|
7
|
+
def self.current
|
8
|
+
Queue.instance.current
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(database_connection, table_name, row_id, &block)
|
12
|
+
throw "Block must be given to target (otherwise, there's no work to do)" unless block_given?
|
13
|
+
|
14
|
+
@table_name = table_name.to_s
|
15
|
+
@row_id = row_id
|
16
|
+
@column_names = []
|
17
|
+
@column_values = []
|
18
|
+
@sql = ''
|
19
|
+
|
20
|
+
target(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def sql
|
24
|
+
@sql
|
25
|
+
end
|
26
|
+
|
27
|
+
def assign(column_name, &block)
|
28
|
+
@column_names << column_name
|
29
|
+
@column_values << block.call
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def target(&block)
|
36
|
+
Queue.instance.push(self)
|
37
|
+
|
38
|
+
yield self
|
39
|
+
|
40
|
+
@sql = "INSERT #{@table_name}"
|
41
|
+
@sql << " (#{pk_name}#{column_names}) VALUES (?#{column_value_markers})"
|
42
|
+
@sql << " ON DUPLICATE KEY UPDATE #{column_markers}"
|
43
|
+
|
44
|
+
execute_sql(@sql)
|
45
|
+
|
46
|
+
Queue.instance.pop
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.targets
|
50
|
+
@@targets
|
51
|
+
end
|
52
|
+
|
53
|
+
def targets
|
54
|
+
@@targets
|
55
|
+
end
|
56
|
+
|
57
|
+
def execute_sql(sql)
|
58
|
+
statement = Database.instance.export.prepare(sql)
|
59
|
+
values = [*column_values] + [*column_values] #array expando
|
60
|
+
statement.send(:execute, @row_id, *values) #expand values into distinct arguments
|
61
|
+
end
|
62
|
+
|
63
|
+
def pk_name
|
64
|
+
'id'
|
65
|
+
end
|
66
|
+
|
67
|
+
def column_names
|
68
|
+
return if @column_names.size == 0
|
69
|
+
",#{@column_names.join(',')}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def column_values
|
73
|
+
@column_values
|
74
|
+
end
|
75
|
+
|
76
|
+
def column_value_markers
|
77
|
+
return if @column_names.size == 0
|
78
|
+
result = ""
|
79
|
+
@column_names.size.times { result << ',?'}
|
80
|
+
result
|
81
|
+
end
|
82
|
+
|
83
|
+
def column_markers
|
84
|
+
return if @column_names.size == 0
|
85
|
+
result = ""
|
86
|
+
@column_names.each {|k| result << "#{k}=?," }
|
87
|
+
result.chop
|
88
|
+
end
|
89
|
+
|
90
|
+
class Queue < DelegateClass(Array)
|
91
|
+
include Singleton
|
92
|
+
|
93
|
+
def current
|
94
|
+
last
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def initialize
|
100
|
+
super([])
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
data/lib/squealer.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.name = "squealer"
|
5
|
+
gemspec.summary = "Document-oriented to Relational database exporter"
|
6
|
+
gemspec.description = "Exports mongodb to mysql. More later."
|
7
|
+
gemspec.email = "joshua.graham@grahamis.com"
|
8
|
+
gemspec.homepage = "http://github.com/deltiscere/squealer/"
|
9
|
+
gemspec.authors = ["Josh Graham", "Durran Jordan"]
|
10
|
+
gem.add_dependency('mysql', '>= 2.8.1')
|
11
|
+
gem.add_dependency('mongo', '>= 0.18.3')
|
12
|
+
end
|
13
|
+
rescue LoadError
|
14
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
15
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'mysql'
|
2
|
+
require 'mongo'
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Squealer::Database do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@db_name = "test_export_#{object_id}"
|
9
|
+
create_test_db(@db_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
after(:all) do
|
13
|
+
drop_test_db(@db_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "is a singleton" do
|
17
|
+
Squealer::Database.respond_to?(:instance).should be_true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "takes an import database" do
|
21
|
+
Squealer::Database.instance.import_from('localhost', 27017, @db_name)
|
22
|
+
Squealer::Database.instance.import.should be_a_kind_of(Mongo::DB)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "takes an export database" do
|
26
|
+
Squealer::Database.instance.export_to('localhost', 'root', '', @db_name)
|
27
|
+
Squealer::Database.instance.export.should be_a_kind_of(Mysql)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def create_test_db(name)
|
33
|
+
@my = Mysql.connect('localhost', 'root')
|
34
|
+
@my.query("create database #{name}")
|
35
|
+
end
|
36
|
+
|
37
|
+
def drop_test_db(name)
|
38
|
+
@my.query("drop database #{name}")
|
39
|
+
@my.close
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Hash do
|
4
|
+
|
5
|
+
describe "#method_missing" do
|
6
|
+
|
7
|
+
it "treats it as a hash key lookup" do
|
8
|
+
{ "name" => "Josh" }.name.should == "Josh"
|
9
|
+
end
|
10
|
+
|
11
|
+
context "with args" do
|
12
|
+
|
13
|
+
it "treats it normally" do
|
14
|
+
lambda { { "name" => "Josh" }.name(nil) }.should raise_error(NoMethodError)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with block" do
|
20
|
+
|
21
|
+
it "treats it normally" do
|
22
|
+
lambda { { "name" => "Josh" }.name {nil} }.should raise_error(NoMethodError)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe NilClass do
|
4
|
+
|
5
|
+
describe "#each" do
|
6
|
+
it "returns an empty array" do
|
7
|
+
nil.each.should == [] # because mongo is schema-less
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe Object do
|
13
|
+
|
14
|
+
describe "#target" do
|
15
|
+
|
16
|
+
it "has been defined" do
|
17
|
+
Object.new.respond_to?(:target).should be_true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "invokes Squealer::Target.new" do
|
21
|
+
Squealer::Target.should_receive(:new)
|
22
|
+
target(:test_table, 1) { nil }
|
23
|
+
end
|
24
|
+
|
25
|
+
it "uses the export database connection" do
|
26
|
+
mock_mysql
|
27
|
+
target(:test_table, 1) { nil }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#assign" do
|
33
|
+
|
34
|
+
it "has been defined" do
|
35
|
+
Object.new.respond_to?(:assign).should be_true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "invokes assign on the target it is immediately nested within" do
|
39
|
+
mock_mysql
|
40
|
+
target(:test_table, 1) do |target1|
|
41
|
+
target1.should_receive(:assign)
|
42
|
+
assign(:colA) { 42 }
|
43
|
+
|
44
|
+
target(:test_table_2, 1) do |target2|
|
45
|
+
target2.should_receive(:assign)
|
46
|
+
assign(:colspeak) { 1984 }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#import" do
|
54
|
+
|
55
|
+
it "has been defined" do
|
56
|
+
Object.new.respond_to?(:import).should be_true
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with a single argument" do
|
60
|
+
|
61
|
+
it "invokes Database.import_from" do
|
62
|
+
Squealer::Database.instance.should_receive(:import_from)
|
63
|
+
import('test_import')
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with no argment" do
|
69
|
+
|
70
|
+
it "invokes Database.import" do
|
71
|
+
Squealer::Database.instance.should_receive(:import)
|
72
|
+
import
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#export" do
|
80
|
+
|
81
|
+
it "has been defined" do
|
82
|
+
Object.new.respond_to?(:export).should be_true
|
83
|
+
end
|
84
|
+
|
85
|
+
context "with a single argument" do
|
86
|
+
|
87
|
+
it "invokes Database.export_to" do
|
88
|
+
Squealer::Database.instance.should_receive(:export_to)
|
89
|
+
export('test_export')
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
context "with no argment" do
|
95
|
+
|
96
|
+
it "invokes Database.export" do
|
97
|
+
Squealer::Database.instance.should_receive(:export)
|
98
|
+
export
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
def mock_mysql
|
106
|
+
my = mock(Mysql)
|
107
|
+
st = mock(Mysql::Stmt)
|
108
|
+
Squealer::Database.instance.should_receive(:export).at_least(:once).and_return(my)
|
109
|
+
my.should_receive(:prepare).at_least(:once).and_return(st)
|
110
|
+
st.should_receive(:execute).at_least(:once)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Squealer::Target do
|
4
|
+
let(:export_dbc) { mock(Mysql) }
|
5
|
+
let(:table_name) { :test_table }
|
6
|
+
let(:row_id) { 0 }
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
Squealer::Database.instance.should_receive(:export).at_least(:once).and_return(export_dbc)
|
10
|
+
st = mock(Mysql::Stmt)
|
11
|
+
export_dbc.should_receive(:prepare).at_least(:once).and_return(st)
|
12
|
+
st.should_receive(:execute).at_least(:once)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "sends the sql to the export database" do
|
16
|
+
Squealer::Target.new(export_dbc, table_name, row_id) { nil }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#target" do
|
20
|
+
|
21
|
+
it "pushes itself onto the targets stack when starting" do
|
22
|
+
@target1 = nil
|
23
|
+
@target2 = nil
|
24
|
+
target1 = Squealer::Target.new(export_dbc, table_name, row_id) do
|
25
|
+
@target1 = Squealer::Target.current
|
26
|
+
Squealer::Target.new(export_dbc, "#{table_name}_2", row_id) do
|
27
|
+
@target2 = Squealer::Target.current
|
28
|
+
@target2.should_not == @target1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
target1.should === @target1
|
32
|
+
end
|
33
|
+
|
34
|
+
it "pops itself off the targets stack when finished" do
|
35
|
+
Squealer::Target.new(export_dbc, table_name, row_id) { nil }
|
36
|
+
Squealer::Target.current.should be_nil
|
37
|
+
end
|
38
|
+
|
39
|
+
context "generates SQL command strings" do
|
40
|
+
|
41
|
+
let(:target) { Squealer::Target.new(export_dbc, table_name, row_id) { nil } }
|
42
|
+
|
43
|
+
it "targets the table" do
|
44
|
+
target.sql.should =~ /^INSERT #{table_name} /
|
45
|
+
end
|
46
|
+
|
47
|
+
it "uses an INSERT ... ON DUPLICATE KEY UPDATE statement" do
|
48
|
+
target.sql.should =~ /^INSERT .* ON DUPLICATE KEY UPDATE /
|
49
|
+
end
|
50
|
+
|
51
|
+
it "includes the primary key name in the INSERT" do
|
52
|
+
target.sql.should =~ / \(id\) VALUES/
|
53
|
+
end
|
54
|
+
|
55
|
+
it "includes the primary key value in the INSERT" do
|
56
|
+
# target.sql.should =~ / VALUES \('#{row_id}'\) /
|
57
|
+
target.sql.should =~ / VALUES \(\?\) /
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
context "with inner block" do
|
63
|
+
|
64
|
+
it "yields inner blocks" do
|
65
|
+
block_done = false
|
66
|
+
target = Squealer::Target.new(export_dbc, table_name, row_id) { block_done = true }
|
67
|
+
block_done.should be_true
|
68
|
+
end
|
69
|
+
|
70
|
+
it "yields inner blocks first" do
|
71
|
+
Squealer::Target.new(export_dbc, table_name, row_id) { Squealer::Target.current.sql.should be_empty }
|
72
|
+
end
|
73
|
+
|
74
|
+
it "yields inner blocks first and they can assign to this target" do
|
75
|
+
target = Squealer::Target.new(export_dbc, table_name, row_id) { Squealer::Target.current.assign(:colA) { 42 } }
|
76
|
+
target.sql.should =~ /colA/
|
77
|
+
# target.sql.should =~ /42/
|
78
|
+
target.sql.should =~ /\?/
|
79
|
+
end
|
80
|
+
|
81
|
+
context "with 2 columns" do
|
82
|
+
|
83
|
+
let(:value_1) { 42 }
|
84
|
+
let(:target) do
|
85
|
+
Squealer::Target.new(export_dbc, table_name, row_id) { Squealer::Target.current.assign(:colA) { value_1 } }
|
86
|
+
end
|
87
|
+
|
88
|
+
it "includes the column name in the INSERT" do
|
89
|
+
target.sql.should =~ /\(id,colA\) VALUES/
|
90
|
+
end
|
91
|
+
|
92
|
+
it "includes the column value in the INSERT" do
|
93
|
+
# target.sql.should =~ /VALUES \('#{row_id}','#{value_1}'\)/
|
94
|
+
target.sql.should =~ /VALUES \(\?,\?\)/
|
95
|
+
end
|
96
|
+
|
97
|
+
it "includes the column name and value in the UPDATE" do
|
98
|
+
# target.sql.should =~ /UPDATE colA='#{value_1}'/
|
99
|
+
target.sql.should =~ /UPDATE colA=\?/
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
context "with 3 columns" do
|
105
|
+
|
106
|
+
let(:value_1) { 42 }
|
107
|
+
let(:value_2) { 'foobar' }
|
108
|
+
let(:target) do
|
109
|
+
Squealer::Target.new(export_dbc, table_name, row_id) do
|
110
|
+
Squealer::Target.current.assign(:colA) { value_1 }
|
111
|
+
Squealer::Target.current.assign(:colB) { value_2 }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it "includes the column names in the INSERT" do
|
116
|
+
target.sql.should =~ /\(id,colA,colB\) VALUES/
|
117
|
+
end
|
118
|
+
|
119
|
+
it "includes the column values in the INSERT" do
|
120
|
+
# target.sql.should =~ /VALUES \('#{row_id}','#{value_1}','#{value_2}'\)/
|
121
|
+
target.sql.should =~ /VALUES \(\?,\?,\?\)/
|
122
|
+
end
|
123
|
+
|
124
|
+
it "includes the column names and values in the UPDATE" do
|
125
|
+
# target.sql.should =~ /UPDATE colA='#{value_1}',colB='#{value_2}'/
|
126
|
+
target.sql.should =~ /UPDATE colA=\?,colB=\?/
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
data/squealer.gemspec
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{squealer}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Josh Graham", "Durran Jordan"]
|
12
|
+
s.date = %q{2010-03-23}
|
13
|
+
s.description = %q{Exports mongodb to mysql. More later.}
|
14
|
+
s.email = %q{joshua.graham@grahamis.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.md"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
".watchr",
|
21
|
+
"README.md",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"lib/example_squeal.rb",
|
25
|
+
"lib/squealer.rb",
|
26
|
+
"lib/squealer/database.rb",
|
27
|
+
"lib/squealer/hash.rb",
|
28
|
+
"lib/squealer/object.rb",
|
29
|
+
"lib/squealer/target.rb",
|
30
|
+
"lib/squealer/time.rb",
|
31
|
+
"lib/tasks/jeweler.rake",
|
32
|
+
"spec/spec.opts",
|
33
|
+
"spec/spec_helper.rb",
|
34
|
+
"spec/squealer/database_spec.rb",
|
35
|
+
"spec/squealer/hash_spec.rb",
|
36
|
+
"spec/squealer/object_spec.rb",
|
37
|
+
"spec/squealer/target_spec.rb",
|
38
|
+
"spec/squealer/time_spec.rb",
|
39
|
+
"squealer.gemspec"
|
40
|
+
]
|
41
|
+
s.homepage = %q{http://github.com/delitescere/squealer/}
|
42
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
43
|
+
s.require_paths = ["lib"]
|
44
|
+
s.rubygems_version = %q{1.3.6}
|
45
|
+
s.summary = %q{Document-oriented to Relational database exporter}
|
46
|
+
s.test_files = [
|
47
|
+
"spec/spec_helper.rb",
|
48
|
+
"spec/squealer/database_spec.rb",
|
49
|
+
"spec/squealer/hash_spec.rb",
|
50
|
+
"spec/squealer/object_spec.rb",
|
51
|
+
"spec/squealer/target_spec.rb",
|
52
|
+
"spec/squealer/time_spec.rb"
|
53
|
+
]
|
54
|
+
|
55
|
+
if s.respond_to? :specification_version then
|
56
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
57
|
+
s.specification_version = 3
|
58
|
+
|
59
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
60
|
+
s.add_runtime_dependency(%q<mysql>, [">= 2.8.1"])
|
61
|
+
s.add_runtime_dependency(%q<mongo>, [">= 0.18.3"])
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<mysql>, [">= 2.8.1"])
|
64
|
+
s.add_dependency(%q<mongo>, [">= 0.18.3"])
|
65
|
+
end
|
66
|
+
else
|
67
|
+
s.add_dependency(%q<mysql>, [">= 2.8.1"])
|
68
|
+
s.add_dependency(%q<mongo>, [">= 0.18.3"])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: squealer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Josh Graham
|
13
|
+
- Durran Jordan
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-03-23 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: mysql
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 2
|
30
|
+
- 8
|
31
|
+
- 1
|
32
|
+
version: 2.8.1
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: mongo
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
- 18
|
45
|
+
- 3
|
46
|
+
version: 0.18.3
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
description: Exports mongodb to mysql. More later.
|
50
|
+
email: joshua.graham@grahamis.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files:
|
56
|
+
- README.md
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- .watchr
|
60
|
+
- README.md
|
61
|
+
- Rakefile
|
62
|
+
- VERSION
|
63
|
+
- lib/example_squeal.rb
|
64
|
+
- lib/squealer.rb
|
65
|
+
- lib/squealer/database.rb
|
66
|
+
- lib/squealer/hash.rb
|
67
|
+
- lib/squealer/object.rb
|
68
|
+
- lib/squealer/target.rb
|
69
|
+
- lib/squealer/time.rb
|
70
|
+
- lib/tasks/jeweler.rake
|
71
|
+
- spec/spec.opts
|
72
|
+
- spec/spec_helper.rb
|
73
|
+
- spec/squealer/database_spec.rb
|
74
|
+
- spec/squealer/hash_spec.rb
|
75
|
+
- spec/squealer/object_spec.rb
|
76
|
+
- spec/squealer/target_spec.rb
|
77
|
+
- spec/squealer/time_spec.rb
|
78
|
+
- squealer.gemspec
|
79
|
+
has_rdoc: true
|
80
|
+
homepage: http://github.com/delitescere/squealer/
|
81
|
+
licenses: []
|
82
|
+
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options:
|
85
|
+
- --charset=UTF-8
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
requirements: []
|
103
|
+
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 1.3.6
|
106
|
+
signing_key:
|
107
|
+
specification_version: 3
|
108
|
+
summary: Document-oriented to Relational database exporter
|
109
|
+
test_files:
|
110
|
+
- spec/spec_helper.rb
|
111
|
+
- spec/squealer/database_spec.rb
|
112
|
+
- spec/squealer/hash_spec.rb
|
113
|
+
- spec/squealer/object_spec.rb
|
114
|
+
- spec/squealer/target_spec.rb
|
115
|
+
- spec/squealer/time_spec.rb
|