mass_insert 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -3
- data/lib/mass_insert/adapters.rb +0 -1
- data/lib/mass_insert/adapters/adapter.rb +1 -7
- data/lib/mass_insert/adapters/column_value.rb +33 -29
- data/lib/mass_insert/adapters/helpers.rb +3 -2
- data/lib/mass_insert/adapters/helpers/abstract_query.rb +48 -0
- data/lib/mass_insert/adapters/helpers/sanitizer.rb +6 -0
- data/lib/mass_insert/adapters/mysql2_adapter.rb +1 -1
- data/lib/mass_insert/base.rb +49 -20
- data/lib/mass_insert/query_builder.rb +6 -6
- data/lib/mass_insert/version.rb +1 -1
- data/spec/active_record_dummy/Gemfile +1 -1
- data/spec/active_record_dummy/config/database.yml +1 -1
- data/spec/mass_insert/adapters/adapter_spec.rb +23 -45
- data/spec/mass_insert/adapters/column_value_spec.rb +107 -154
- data/spec/mass_insert/adapters/{abstract_query_spec.rb → helpers/abstract_query_spec.rb} +23 -27
- data/spec/mass_insert/adapters/helpers/sanitizer_spec.rb +16 -9
- data/spec/mass_insert/adapters/helpers/timestamp_spec.rb +11 -15
- data/spec/mass_insert/adapters/helpers_spec.rb +7 -3
- data/spec/mass_insert/adapters/mysql_adapter_spec.rb +6 -10
- data/spec/mass_insert/adapters/postgresql_adapter_spec.rb +4 -8
- data/spec/mass_insert/adapters/sqlite3_adapter_spec.rb +24 -30
- data/spec/mass_insert/adapters/sqlserver_adapter_spec.rb +16 -21
- data/spec/mass_insert/adapters_spec.rb +8 -12
- data/spec/mass_insert/base_spec.rb +13 -13
- data/spec/mass_insert/process_control_spec.rb +33 -40
- data/spec/mass_insert/query_builder_spec.rb +20 -24
- data/spec/mass_insert/query_execution_spec.rb +13 -16
- data/spec/mass_insert_spec.rb +6 -6
- metadata +7 -7
- data/lib/mass_insert/adapters/abstract_query.rb +0 -47
data/README.md
CHANGED
@@ -77,15 +77,15 @@ OR directly
|
|
77
77
|
|
78
78
|
Some options that you can include are...
|
79
79
|
|
80
|
-
|
80
|
+
`:table_name` : Default value is the table name to your model. This options rarely needs to change but you can do it if you pass a string with the table name. Example...
|
81
81
|
|
82
82
|
options = {:table_name => "users"}
|
83
83
|
|
84
|
-
|
84
|
+
`:primary_key` : Default value is `:id`. You can change the name of primary key column send it a symbol with the column name.
|
85
85
|
|
86
86
|
options = {:primary_key => :post_id}
|
87
87
|
|
88
|
-
|
88
|
+
`:primary_key_mode` : Default value is `:auto`. When is `:auto` MassInsert knows that the database will generate the value of the primary key column automatically. If you pass `:manual` as primary key mode you need to create your value hashes with the key and value of the primary key column.
|
89
89
|
|
90
90
|
options = {:primary_key_mode => :manual}
|
91
91
|
|
data/lib/mass_insert/adapters.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
module MassInsert
|
2
2
|
module Adapters
|
3
3
|
autoload :Adapter, 'mass_insert/adapters/adapter.rb'
|
4
|
-
autoload :AbstractQuery, 'mass_insert/adapters/abstract_query.rb'
|
5
4
|
autoload :ColumnValue, 'mass_insert/adapters/column_value.rb'
|
6
5
|
autoload :Helpers, 'mass_insert/adapters/helpers.rb'
|
7
6
|
autoload :Mysql2Adapter, 'mass_insert/adapters/mysql2_adapter.rb'
|
@@ -4,7 +4,7 @@ module MassInsert
|
|
4
4
|
# be executed. The methods here provides a functionality that be required
|
5
5
|
# in all the adapters.
|
6
6
|
class Adapter
|
7
|
-
include AbstractQuery
|
7
|
+
include Helpers::AbstractQuery
|
8
8
|
include Helpers::Timestamp
|
9
9
|
include Helpers::Sanitizer
|
10
10
|
|
@@ -27,12 +27,6 @@ module MassInsert
|
|
27
27
|
options[:table_name]
|
28
28
|
end
|
29
29
|
|
30
|
-
# Returns an array with the column names in the database table like
|
31
|
-
# a symbols.
|
32
|
-
def table_columns
|
33
|
-
class_name.column_names.map(&:to_sym)
|
34
|
-
end
|
35
|
-
|
36
30
|
# Returns the array with the column names valid to be included into the
|
37
31
|
# query string according to the options.
|
38
32
|
def column_names
|
@@ -49,15 +49,17 @@ module MassInsert
|
|
49
49
|
|
50
50
|
# Returns a single column string value with the correct format and
|
51
51
|
# according to the database configuration, column type and presence.
|
52
|
+
# If the row hash does not include the value to this column return the
|
53
|
+
# default value according to database configuration.
|
52
54
|
def build
|
53
|
-
|
55
|
+
column_value.nil? ? default_value : send(:"column_value_#{column_type}")
|
54
56
|
end
|
55
57
|
|
56
58
|
# Returns the correct value when the column value is string, text,
|
57
|
-
# date, time, datetime, timestamp. There are alias
|
59
|
+
# date, time, datetime, timestamp. There are alias methods to the
|
58
60
|
# other column types that need a similar query value.
|
59
61
|
def column_value_string
|
60
|
-
|
62
|
+
"'#{column_value}'"
|
61
63
|
end
|
62
64
|
alias :column_value_text :column_value_string
|
63
65
|
alias :column_value_date :column_value_string
|
@@ -66,40 +68,42 @@ module MassInsert
|
|
66
68
|
alias :column_value_timestamp :column_value_string
|
67
69
|
alias :column_value_binary :column_value_string
|
68
70
|
|
69
|
-
# Returns the correct value to column
|
70
|
-
#
|
71
|
-
#
|
71
|
+
# Returns the correct value to integer column. The column values is
|
72
|
+
# converted to integer to be sure that the value is correct to be
|
73
|
+
# persisted into the database and after it, it's converted to string.
|
72
74
|
def column_value_integer
|
73
|
-
column_value.
|
75
|
+
column_value.to_i.to_s
|
74
76
|
end
|
75
77
|
|
76
|
-
# Returns the correct value to column
|
77
|
-
#
|
78
|
-
# value to
|
79
|
-
#
|
78
|
+
# Returns the correct value to decimal column. There is an alias method
|
79
|
+
# to float type. The column values is converted to decimal to be sure
|
80
|
+
# that the value is correct to be persisted into the database and after
|
81
|
+
# it, it's converted to string.
|
80
82
|
def column_value_decimal
|
81
|
-
column_value.
|
83
|
+
column_value.to_f.to_s
|
82
84
|
end
|
83
85
|
alias :column_value_float :column_value_decimal
|
84
86
|
|
85
|
-
# Returns the correct value to column
|
86
|
-
#
|
87
|
-
# value
|
87
|
+
# Returns the correct value to boolean column. This column calls the
|
88
|
+
# correct method according to the database adapter to return the correct
|
89
|
+
# value to that database engine.
|
88
90
|
def column_value_boolean
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
91
|
+
self.send(:"#{adapter}_column_value_boolean")
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the column value to boolean column like a string. If the
|
95
|
+
# column value exists returns a true string else false string. There
|
96
|
+
# are alias methods to the database engines that works similarity.
|
97
|
+
def mysql2_column_value_boolean
|
98
|
+
column_value ? "true" : "false"
|
99
|
+
end
|
100
|
+
alias :postgresql_column_value_boolean :mysql2_column_value_boolean
|
101
|
+
alias :sqlserver_column_value_boolean :mysql2_column_value_boolean
|
102
|
+
|
103
|
+
# Returns the column value to boolean column like a string. If the
|
104
|
+
# column value exists returns a "1" else "0".
|
105
|
+
def sqlite3_column_value_boolean
|
106
|
+
column_value ? "1" : "0"
|
103
107
|
end
|
104
108
|
|
105
109
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module MassInsert
|
2
2
|
module Adapters
|
3
3
|
module Helpers
|
4
|
-
autoload :
|
5
|
-
autoload :
|
4
|
+
autoload :AbstractQuery, 'mass_insert/adapters/helpers/abstract_query.rb'
|
5
|
+
autoload :Timestamp, 'mass_insert/adapters/helpers/timestamp.rb'
|
6
|
+
autoload :Sanitizer, 'mass_insert/adapters/helpers/sanitizer.rb'
|
6
7
|
end
|
7
8
|
end
|
8
9
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module MassInsert
|
2
|
+
module Adapters
|
3
|
+
module Helpers
|
4
|
+
module AbstractQuery
|
5
|
+
|
6
|
+
# Returns a begin string to a basic mysql query insertion. Include
|
7
|
+
# the class table_name and it's included in the string.
|
8
|
+
def begin_string
|
9
|
+
"INSERT INTO #{table_name} "
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns a string with the column names to the class table name
|
13
|
+
# and divided by commas.
|
14
|
+
def string_columns
|
15
|
+
"(#{column_names.join(", ")}) "
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the string with all the row values that will be included
|
19
|
+
# in the sql string.
|
20
|
+
def string_values
|
21
|
+
"VALUES (#{string_rows_values});"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Gives the correct format to the values string to all rows. This
|
25
|
+
# functions calls a function that will generate a single string row
|
26
|
+
# and at the end all the strings are concatenated.
|
27
|
+
def string_rows_values
|
28
|
+
values.map{ |row| string_single_row_values(row) }.join("), (")
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the row column values string to be added in query string
|
32
|
+
# according to the type column and values.
|
33
|
+
# Before that row is prepared with the correct values.
|
34
|
+
def string_single_row_values row
|
35
|
+
row.merge!(timestamp_values) if timestamp?
|
36
|
+
column_names.map{ |col| string_single_value(row, col) }.join(", ")
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns a single column string value with the correct format and
|
40
|
+
# according to the database configuration, column type and presence.
|
41
|
+
def string_single_value row, column
|
42
|
+
ColumnValue.new(row, column, options).build
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -3,6 +3,12 @@ module MassInsert
|
|
3
3
|
module Helpers
|
4
4
|
module Sanitizer
|
5
5
|
|
6
|
+
# Returns an array with the column names in the database table like
|
7
|
+
# a symbols.
|
8
|
+
def table_columns
|
9
|
+
class_name.column_names.map(&:to_sym)
|
10
|
+
end
|
11
|
+
|
6
12
|
# Update the array with the columns names according to the options
|
7
13
|
# and prepare the columns array with only valid columns.
|
8
14
|
def sanitized_columns
|
@@ -5,7 +5,7 @@ module MassInsert
|
|
5
5
|
# This method is overwrite because the timestamp format to this
|
6
6
|
# database engine does not need precision in nanoseconds.
|
7
7
|
def timestamp_format
|
8
|
-
|
8
|
+
"%Y-%m-%d %H:%M:%S"
|
9
9
|
end
|
10
10
|
|
11
11
|
# This functions calls the necessary functions to create a complete
|
data/lib/mass_insert/base.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
module MassInsert
|
2
2
|
module Base
|
3
3
|
|
4
|
-
#
|
4
|
+
# = MassInsert
|
5
|
+
#
|
6
|
+
# This method does a mass database insertion just calling it from your
|
7
|
+
# ActiveRecord model. Example...
|
5
8
|
#
|
6
9
|
# User.mass_insert(values)
|
7
10
|
#
|
@@ -14,21 +17,52 @@ module MassInsert
|
|
14
17
|
# {:name => "user name", :email => "user email"}
|
15
18
|
# ]
|
16
19
|
#
|
20
|
+
# == Options
|
21
|
+
#
|
22
|
+
# And MassInset gem allow you to send it some options as second param
|
23
|
+
# Example...
|
24
|
+
#
|
25
|
+
# User.mass_insert(values, options)
|
26
|
+
#
|
27
|
+
# === table_name
|
28
|
+
#
|
29
|
+
# Default value is the table name to your model. This options rarely
|
30
|
+
# needs to change but you can do it if you pass a string with the table
|
31
|
+
# name. Example...
|
32
|
+
#
|
33
|
+
# options = {:table_name => "users"}
|
34
|
+
#
|
35
|
+
# === primary_key
|
36
|
+
#
|
37
|
+
# Default value is :id. You can change the name of primary key column
|
38
|
+
# send it a symbol with the column name.
|
39
|
+
#
|
40
|
+
# options = {:primary_key => :post_id}
|
41
|
+
#
|
42
|
+
# === primary_key_mode
|
43
|
+
#
|
44
|
+
# Default value is :auto. When is :auto MassInsert knows that database
|
45
|
+
# will generate the value of the primary key column automatically. If
|
46
|
+
# you pass :manual as primary key mode you need to create your value
|
47
|
+
# hashes with the key and value of the primary key column.
|
48
|
+
#
|
49
|
+
# options = {:primary_key_mode => :manual}
|
50
|
+
#
|
17
51
|
# When a class that inherit from ActiveRecord::Base calls this method
|
18
52
|
# is going to extend the methods in ClassMethods module. This module
|
19
53
|
# contains some methods that provides some necessary functionality.
|
20
54
|
#
|
21
55
|
# After extends the class with methods in ClassMethods module. The
|
22
56
|
# options that were passed by params are sanitized in the method
|
23
|
-
# called
|
24
|
-
#
|
57
|
+
# called mass_insert_options to be passed by params to ProcessControl
|
58
|
+
# class. The record values are passed too.
|
25
59
|
def mass_insert values, args = {}
|
26
60
|
class_eval do
|
27
61
|
extend ClassMethods
|
28
62
|
end
|
29
63
|
|
30
64
|
options = mass_insert_options(args)
|
31
|
-
@mass_insert_process =
|
65
|
+
@mass_insert_process = ProcessControl.new(values, options)
|
32
66
|
@mass_insert_process.start
|
33
67
|
end
|
34
68
|
|
@@ -43,22 +77,17 @@ module MassInsert
|
|
43
77
|
end
|
44
78
|
|
45
79
|
private
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
args[:primary_key_mode] ||= :auto
|
58
|
-
|
59
|
-
# Returns the arguments but sanitized and ready to be used. This
|
60
|
-
# args will be passed by params to ProcessControl class.
|
61
|
-
args
|
80
|
+
# Sanitizes the MassInset options that were passed by params.
|
81
|
+
# Prepares default options that come in the class that invokes the
|
82
|
+
# mass_insert function and attributes options that were configured
|
83
|
+
# and if the options weren't passed, they would be initialized with
|
84
|
+
# the default values.
|
85
|
+
def mass_insert_options options = {}
|
86
|
+
options[:class_name] ||= self
|
87
|
+
options[:table_name] ||= self.table_name
|
88
|
+
options[:primary_key] ||= :id
|
89
|
+
options[:primary_key_mode] ||= :auto
|
90
|
+
options
|
62
91
|
end
|
63
92
|
|
64
93
|
end
|
@@ -12,7 +12,7 @@ module MassInsert
|
|
12
12
|
# sql string ready to be executed and returns it to be execute in
|
13
13
|
# the QueryExecution class.
|
14
14
|
def build
|
15
|
-
|
15
|
+
adapter_class.new(values, options).execute
|
16
16
|
end
|
17
17
|
|
18
18
|
# Returns a string that contains the adapter type previosly
|
@@ -25,16 +25,16 @@ module MassInsert
|
|
25
25
|
# instance will be called to generate the sql string. The values
|
26
26
|
# and options are passed by params when the correct adapter class
|
27
27
|
# is instanced.
|
28
|
-
def
|
28
|
+
def adapter_class
|
29
29
|
case adapter
|
30
30
|
when "mysql2"
|
31
|
-
Adapters::Mysql2Adapter
|
31
|
+
Adapters::Mysql2Adapter
|
32
32
|
when "postgresql"
|
33
|
-
Adapters::PostgreSQLAdapter
|
33
|
+
Adapters::PostgreSQLAdapter
|
34
34
|
when "sqlite3"
|
35
|
-
Adapters::SQLite3Adapter
|
35
|
+
Adapters::SQLite3Adapter
|
36
36
|
when "sqlserver"
|
37
|
-
Adapters::SQLServerAdapter
|
37
|
+
Adapters::SQLServerAdapter
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
data/lib/mass_insert/version.rb
CHANGED
@@ -8,7 +8,7 @@ gem 'rails', '3.2.13'
|
|
8
8
|
gem 'sqlite3'
|
9
9
|
gem 'mysql2'
|
10
10
|
gem 'pg'
|
11
|
-
gem 'mass_insert'
|
11
|
+
gem 'mass_insert'
|
12
12
|
|
13
13
|
# Gems used only for assets and not required
|
14
14
|
# in production environments by default.
|
@@ -3,113 +3,91 @@ require "./lib/mass_insert"
|
|
3
3
|
require "./spec/dummy_models/test"
|
4
4
|
|
5
5
|
describe MassInsert::Adapters::Adapter do
|
6
|
-
|
7
|
-
@adapter = MassInsert::Adapters::Adapter.new([], {})
|
8
|
-
end
|
9
|
-
|
10
|
-
subject{ @adapter }
|
6
|
+
let!(:subject){ MassInsert::Adapters::Adapter.new([], {}) }
|
11
7
|
|
12
8
|
describe "instance methods" do
|
13
9
|
describe "#initialize" do
|
14
|
-
|
15
|
-
before :each do
|
16
|
-
@values = [{:name => "name"}]
|
17
|
-
@options = {:option_one => 10}
|
18
|
-
@adapter = MassInsert::Adapters::Adapter.new(@values, @options)
|
19
|
-
end
|
10
|
+
let(:adapter){MassInsert::Adapters::Adapter.new("values", "options")}
|
20
11
|
|
21
12
|
it "should initialize the values" do
|
22
|
-
|
13
|
+
expect(adapter.values).to eq("values")
|
23
14
|
end
|
24
15
|
|
25
16
|
it "should initialize the options" do
|
26
|
-
|
17
|
+
expect(adapter.options).to eq("options")
|
27
18
|
end
|
28
19
|
end
|
29
20
|
|
30
21
|
describe "#class_name" do
|
31
22
|
it "should respond to class name method" do
|
32
|
-
subject.respond_to
|
23
|
+
expect(subject).to respond_to(:class_name)
|
33
24
|
end
|
34
25
|
|
35
26
|
it "should returns the class_name in options" do
|
36
27
|
subject.options = {:class_name => Test}
|
37
|
-
subject.class_name.
|
28
|
+
expect(subject.class_name).to eq(Test)
|
38
29
|
end
|
39
30
|
end
|
40
31
|
|
41
32
|
describe "#table_name" do
|
42
33
|
it "should respond to table_name method" do
|
43
|
-
subject.respond_to
|
34
|
+
expect(subject).to respond_to(:table_name)
|
44
35
|
end
|
45
36
|
|
46
37
|
it "should returns the table_name in options" do
|
47
38
|
subject.options = {:table_name => "users"}
|
48
|
-
subject.table_name.
|
39
|
+
expect(subject.table_name).to eq("users")
|
49
40
|
end
|
50
41
|
end
|
51
42
|
|
52
|
-
describe "#
|
53
|
-
|
54
|
-
subject.
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
columns = [:id, :name, :email]
|
60
|
-
subject.table_columns.should eq(columns)
|
43
|
+
describe "#column_names" do
|
44
|
+
before :each do
|
45
|
+
subject.options.merge!({
|
46
|
+
:class_name => Test,
|
47
|
+
:primary_key => :id,
|
48
|
+
:primary_key_mode => :auto
|
49
|
+
})
|
61
50
|
end
|
62
|
-
end
|
63
51
|
|
64
|
-
describe "#column_names" do
|
65
52
|
it "should respond to column_names method" do
|
66
|
-
subject.respond_to
|
53
|
+
expect(subject).to respond_to(:column_names)
|
67
54
|
end
|
68
55
|
|
69
56
|
context "when primary_key is auto" do
|
70
57
|
it "should return an array without primary key column" do
|
71
|
-
subject.options.merge!({
|
72
|
-
:class_name => Test,
|
73
|
-
:primary_key => :id,
|
74
|
-
:primary_key_mode => :auto
|
75
|
-
})
|
76
58
|
column_names = [:name, :email]
|
77
|
-
subject.column_names.
|
59
|
+
expect(subject.column_names).to eq(column_names)
|
78
60
|
end
|
79
61
|
end
|
80
62
|
|
81
63
|
context "when primary key is manual" do
|
82
64
|
it "should return an array with primary key column" do
|
83
|
-
subject.options.merge!({
|
84
|
-
:class_name => Test,
|
85
|
-
:primary_key => :id,
|
86
|
-
:primary_key_mode => :manual
|
87
|
-
})
|
65
|
+
subject.options.merge!({:primary_key_mode => :manual})
|
88
66
|
column_names = [:id, :name, :email]
|
89
|
-
subject.column_names.
|
67
|
+
expect(subject.column_names).to eq(column_names)
|
90
68
|
end
|
91
69
|
end
|
92
70
|
end
|
93
71
|
|
94
72
|
describe "#primary_key" do
|
95
73
|
it "should respond to primary_key method" do
|
96
|
-
subject.respond_to
|
74
|
+
expect(subject).to respond_to(:primary_key)
|
97
75
|
end
|
98
76
|
|
99
77
|
it "should returns the primary_key in options" do
|
100
78
|
subject.options = {:primary_key => :user_id}
|
101
|
-
subject.primary_key.
|
79
|
+
expect(subject.primary_key).to eq(:user_id)
|
102
80
|
end
|
103
81
|
end
|
104
82
|
|
105
83
|
describe "#primary_key_mode" do
|
106
84
|
it "should respond to primary_key_mode method" do
|
107
|
-
subject.respond_to
|
85
|
+
expect(subject).to respond_to(:primary_key_mode)
|
108
86
|
end
|
109
87
|
|
110
88
|
it "should returns the primary_key_mode in options" do
|
111
89
|
subject.options = {:primary_key_mode => :auto}
|
112
|
-
subject.primary_key_mode.
|
90
|
+
expect(subject.primary_key_mode).to eq(:auto)
|
113
91
|
end
|
114
92
|
end
|
115
93
|
|