Permalink
Browse files

Move to datamapper/do (data_objects)

Remove typecasting that DataObjects does anyway.
Handle :_id key in source hashmap.
  • Loading branch information...
1 parent c0cfe7e commit 44c07a65a265de69fc1771f887e7eb76ee252cba Josh Graham and Tim Pope committed with Jun 21, 2010
View
1 lib/squealer.rb
@@ -1,6 +1,5 @@
require 'squealer/hash'
require 'squealer/object'
-require 'squealer/time'
require 'squealer/database'
require 'squealer/progress_bar'
View
9 lib/squealer/database.rb
@@ -1,5 +1,8 @@
-require 'mysql'
require 'mongo'
+require 'data_objects'
+require 'mysql'
+require 'do_mysql'
+
require 'singleton'
module Squealer
@@ -12,15 +15,15 @@ def import_from(host, port, name)
end
def export_to(host, username, password, name)
- @export_dbc = Mysql.connect(host, username, password, name)
+ @export_do = DataObjects::Connection.new("mysql://#{username}:#{password}@#{host}/#{name}")
end
def import
@import_connection
end
def export
- @export_dbc
+ @export_do
end
class Connection
View
1 lib/squealer/hash.rb
@@ -1,6 +1,7 @@
class Hash
def method_missing(name, *args, &block)
super if args.size > 0 || block_given?
+ #TODO: Warn if key doesn't exist - it's probably a typo in their squealer script
self[name.to_s]
end
end
View
16 lib/squealer/target.rb
@@ -55,13 +55,13 @@ def obtain_row_id(row_id)
end
def infer_row_id
- eval "#{@table_name}._id", @binding, __FILE__, __LINE__
+ (eval "#{@table_name}._id", @binding, __FILE__, __LINE__).to_s
end
def verify_table_name_in_scope
table = eval "#{@table_name}", @binding, __FILE__, __LINE__
raise ArgumentError, "The variable '#{@table_name}' is not a hashmap" unless table.is_a? Hash
- raise ArgumentError, "The hashmap '#{@table_name}' must have an '_id' key" unless table.has_key? '_id'
+ raise ArgumentError, "The hashmap '#{@table_name}' must have an '_id' key" unless table.has_key?('_id') || table.has_key?(:_id)
rescue NameError
raise NameError, "A variable named '#{@table_name}' must be in scope, and reference a hashmap with at least an '_id' key."
end
@@ -102,10 +102,8 @@ def targets
end
def execute_sql(sql)
- statement = Database.instance.export.prepare(sql)
values = typecast_values * 2
-
- statement.send(:execute, @row_id, *values) #expand values into distinct arguments
+ Database.instance.export.create_command(sql).execute_non_query(infer_row_id, *values)
rescue Mysql::Error, TypeError
raise "Failed to execute statement: #{sql} with #{values.inspect}.\nOriginal Exception was: #{$!.to_s}"
end
@@ -140,14 +138,10 @@ def column_markers
def typecast_values
column_values.map do |value|
case value
- when true
- 1
- when false
- 0
- when Symbol
- value.to_s
when Array
value.join(",")
+ when BSON::ObjectID
+ value.to_s
else
value
end
View
5 lib/squealer/time.rb
@@ -1,5 +0,0 @@
-class Time
- def to_s
- strftime("%Y-%m-%d %H:%M:%S %Z")
- end
-end
View
95 spec/integration/export_a_record_spec.rb
@@ -0,0 +1,95 @@
+require 'spec_helper'
+
+describe "Exporting" do
+ before do
+ truncate_export_tables
+ end
+
+ let(:databases) { Squealer::Database.instance }
+
+ def prepare_export_database
+ databases.export_to('localhost', 'root', '', $db_name)
+ end
+
+ def squeal_basic_users_document(user=users_document)
+ target(:user) do
+ assign(:name)
+ assign(:organization_id)
+ assign(:dob)
+ assign(:gender)
+ assign(:awesome)
+ assign(:fat)
+ assign(:symbolic)
+ assign(:interests)
+ end
+ end
+
+ let :users_document do
+ { :_id => 'ABCDEFGHIJKLMNOPQRSTUVWX',
+ 'name' => 'Test User', 'dob' => as_time(Date.parse('04-Jul-1776')), 'gender' => 'M',
+ 'awesome' => true,
+ 'fat' => false,
+ 'symbolic' => :of_course,
+ 'interests' => ['health', 'education'],
+ 'organization_id' => '123456789012345678901234',
+ 'activities' => [
+ { 'name' => 'Be independent', 'due_date' => as_time(Date.today + 1) },
+ { 'name' => 'Fight each other', 'due_date' => as_time(Date.today + 7) }
+ ]
+ }
+ end
+
+ let :first_users_record do
+ dbc = databases.instance_variable_get('@export_do')
+ reader = dbc.create_command('SELECT * FROM user').execute_reader
+ reader.each { |x| break x }
+ end
+
+ context "a new record" do
+ it "saves the data correctly" do
+ prepare_export_database
+ squeal_basic_users_document
+ result = first_users_record
+
+ result['name'].should == 'Test User'
+
+ result['dob'].mday.should == 4
+ result['dob'].mon.should == 7
+ result['dob'].year.should == 1776
+
+ result['gender'].should == 'M'
+
+ result['awesome'].should be_true
+ result['fat'].should be_false
+
+ result['symbolic'].should == :of_course.to_s
+
+ result['interests'].should == 'health,education'
+ end
+ end
+
+ context "an existing record" do
+ it "updates the data correctly" do
+ prepare_export_database
+ squeal_basic_users_document
+ squeal_basic_users_document(users_document.merge('awesome' => false, 'gender' => 'F'))
+
+ result = first_users_record
+
+ result['name'].should == 'Test User'
+
+ result['dob'].mday.should == 4
+ result['dob'].mon.should == 7
+ result['dob'].year.should == 1776
+
+ result['gender'].should == 'F'
+
+ result['awesome'].should be_false
+ result['fat'].should be_false
+
+ result['symbolic'].should == :of_course.to_s
+
+ result['interests'].should == 'health,education'
+ end
+ end
+end
View
58 spec/spec_helper.rb
@@ -18,11 +18,10 @@
end
def create_test_db(name)
- @my = Mysql.connect('localhost', 'root')
- @my.query("DROP DATABASE IF EXISTS #{name}")
- @my.query("CREATE DATABASE #{name}")
- @my.query("USE #{name}")
- @my.query("SET sql_mode='ANSI_QUOTES'")
+ dbc = DataObjects::Connection.new("mysql://root@localhost/mysql")
+ dbc.create_command("DROP DATABASE IF EXISTS #{name}").execute_non_query
+ dbc.create_command("CREATE DATABASE #{name}").execute_non_query
+ dbc.create_command("SET sql_mode='ANSI_QUOTES'").execute_non_query
create_export_tables
@@ -33,8 +32,10 @@ def create_test_db(name)
end
def drop_test_db(name)
- @my.query("DROP DATABASE IF EXISTS #{name}")
- @my.close
+ @my.close if @my
+ dbc = DataObjects::Connection.new("mysql://root@localhost/mysql")
+ dbc.create_command("DROP DATABASE IF EXISTS #{name}").execute_non_query
+ dbc.close
drop_mongo
end
@@ -78,35 +79,54 @@ def seed_import
def create_export_tables
command = <<-COMMAND.gsub(/\n\s*/, " ")
- CREATE TABLE "users" (
- "id" INT NOT NULL AUTO_INCREMENT ,
+ CREATE TABLE "user" (
+ "id" CHAR(24) NOT NULL ,
+ "organization_id" CHAR(24) NOT NULL ,
"name" VARCHAR(255) NULL ,
"gender" CHAR(1) NULL ,
- "dob" DATE NULL ,
+ "dob" DATETIME NULL ,
+ "awesome" BOOLEAN NULL ,
+ "fat" BOOLEAN NULL ,
+ "symbolic" VARCHAR(255) NULL ,
+ "interests" TEXT NULL ,
PRIMARY KEY ("id") )
COMMAND
- @my.query(command)
+ non_query(command)
command = <<-COMMAND.gsub(/\n\s*/, " ")
CREATE TABLE "activity" (
- "id" INT NOT NULL AUTO_INCREMENT ,
- "user_id" INT NULL ,
+ "id" CHAR(24) NOT NULL ,
+ "user_id" CHAR(24) NULL ,
"name" VARCHAR(255) NULL ,
- "due_date" DATE NULL ,
+ "due_date" DATETIME NULL ,
PRIMARY KEY ("id") )
COMMAND
- @my.query(command)
+ non_query(command)
command = <<-COMMAND.gsub(/\n\s*/, " ")
- CREATE TABLE "organizations" (
- "id" INT NOT NULL AUTO_INCREMENT ,
- "disabed_date" DATE NULL ,
+ CREATE TABLE "organization" (
+ "id" CHAR(24) NOT NULL ,
+ "disabled_date" DATETIME NULL ,
PRIMARY KEY ("id") )
COMMAND
- @my.query(command)
+ non_query(command)
+ end
+
+ def truncate_export_tables
+ non_query('DELETE FROM "user"')
+ non_query('TRUNCATE TABLE "activity"')
+ non_query('TRUNCATE TABLE "organization"')
end
def as_time(date)
Time.parse(date.to_s)
end
+
+ def non_query(text)
+ my.create_command(text).execute_non_query
+ end
+
+ def my
+ @my ||= DataObjects::Connection.new("mysql://root@localhost/#{$db_name}")
+ end
end
View
30 spec/squealer/database_spec.rb
@@ -1,5 +1,4 @@
require 'spec_helper'
-require 'mysql'
require 'mongo'
describe Squealer::Database do
@@ -105,14 +104,25 @@
end
context "real squeal" do
- before { pending "interactive_view" }
- subject do
- source = databases.import.source("users")
- end
-
- it "^^^ you saw that progress bar right there" do
- subject.each do
- sleep (rand(2) + 1)
+ # before { pending "interactive_view" }
+ it "exports that stuff to mysql" do
+ databases.export_to('localhost', 'root', '', $db_name)
+ databases.import.source("users").each do |user|
+ target(:user) do |target|
+ target.instance_variable_get('@row_id').should == user['_id'].to_s
+ assign(:organization_id)
+ assign(:name)
+
+ #TODO: What about _id from embedded docs that aren't Mongoid managed?
+ # users.activities.each do |activities|
+ # p activities
+ # target(:activities) do |target|
+ # assign(:user_id)
+ # assign(:name)
+ # assign(:due_date)
+ # end
+ # end
+ end
end
end
end
@@ -126,7 +136,7 @@
it "takes an export database" do
databases.export_to('localhost', 'root', '', $db_name)
- databases.send(:instance_variable_get, '@export_dbc').should be_a_kind_of(Mysql)
+ databases.instance_variable_get('@export_do').should_not be_nil
end
end
View
8 spec/squealer/object_spec.rb
@@ -112,11 +112,11 @@
end
def mock_mysql
- my = mock(Mysql)
- st = mock(Mysql::Stmt)
+ my = mock(DataObjects::Connection)
+ comm = mock(DataObjects::Command)
Squealer::Database.instance.should_receive(:export).at_least(:once).and_return(my)
- my.should_receive(:prepare).at_least(:once).and_return(st)
- st.should_receive(:execute).at_least(:once)
+ my.should_receive(:create_command).at_least(:once).and_return(comm)
+ comm.should_receive(:execute_non_query).at_least(:once)
end
end
View
26 spec/squealer/target_spec.rb
@@ -11,7 +11,7 @@
context "targeting" do
describe "initialize" do
- let(:faqs) { [{'_id' => 123}] }
+ let(:faqs) { [{'_id' => '123'}] }
context "without a target row id" do
context "with the inferred variable in scope" do
@@ -217,21 +217,6 @@
target.assign(:colA) { ['1', '2'] }
subject.should == ['1,2']
end
-
- it "casts false to 0 (for mysql TINYINT)" do
- target.assign(:colA) { false }
- subject.should == [0]
- end
-
- it "casts true to 1 (for mysql TINYINT)" do
- target.assign(:colA) { true }
- subject.should == [1]
- end
-
- it "casts symbol to string" do
- target.assign(:colA) { :open }
- subject.should == ['open']
- end
end
context "generates SQL command strings" do
@@ -307,8 +292,9 @@
end
def mock_mysql
- Squealer::Database.instance.should_receive(:export).at_least(:once).and_return(export_dbc)
- st = mock(Mysql::Stmt)
- export_dbc.should_receive(:prepare).at_least(:once).and_return(st)
- st.should_receive(:execute).at_least(:once)
+ my = mock(DataObjects::Connection)
+ comm = mock(DataObjects::Command)
+ Squealer::Database.instance.should_receive(:export).at_least(:once).and_return(my)
+ my.should_receive(:create_command).at_least(:once).and_return(comm)
+ comm.should_receive(:execute_non_query).at_least(:once)
end
View
10 spec/squealer/time_spec.rb
@@ -1,10 +0,0 @@
-require 'spec_helper'
-
-describe Time do
-
- describe "#to_s" do
- it "uses a MySQL compliant format" do
- Time.gm(2000,"Jan",31).to_s.should == "2000-01-31 00:00:00 UTC"
- end
- end
-end

0 comments on commit 44c07a6

Please sign in to comment.