mass_insert 0.0.2 → 0.0.3
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/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
|
|