multi_insert 0.2.1 → 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.
- checksums.yaml +4 -4
- data/lib/multi_insert/hooks/active_record.rb +8 -0
- data/lib/multi_insert/query.rb +64 -0
- data/lib/multi_insert/query_builder.rb +4 -3
- data/lib/multi_insert/version.rb +2 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09249bbd92253e001ba2eda9b5229ba076f5fa47'
|
4
|
+
data.tar.gz: fa5a964166797cce48283e4dfd2dd1baf2426fd3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 507b36948e987722d93c623bfa5a743fddd970d03926439f81b5c577f75da3dc5c5aeb2a1d23162e362fe2c8df1f27670a003efd8b6d2e88914f2c85b076e3c2
|
7
|
+
data.tar.gz: 2bd855e0af71b62829b7be80d7d3e452fcce4c7de3079299b6b56d8b1ff4d67f48649cb9d5180d136f87b6f282bee8805d3b18784fdece2309150effd9fd4bf2
|
@@ -2,6 +2,14 @@ require 'active_record'
|
|
2
2
|
require 'multi_insert/query'
|
3
3
|
|
4
4
|
class ActiveRecord::Base
|
5
|
+
# Start a multi insert.
|
6
|
+
#
|
7
|
+
# See `Query#new` for a list of options.
|
8
|
+
#
|
9
|
+
# @param columns [Array<Symbol | String>] The columns to use for insertion.
|
10
|
+
# @param values [Array<Array<String | Number | Boolean | nil>>] Values to be inserted.
|
11
|
+
# @param opts [Hash<Object>] Options.
|
12
|
+
# @return [Query] A query object.
|
5
13
|
def self.multi_insert(columns, values, opts = {})
|
6
14
|
::MultiInsert::Query.new(self.table_name, columns, values, opts)
|
7
15
|
end
|
data/lib/multi_insert/query.rb
CHANGED
@@ -1,18 +1,43 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'multi_insert/query_builder'
|
3
3
|
|
4
|
+
# Top level module for MultiInsert.
|
4
5
|
module MultiInsert
|
6
|
+
# A MultiInsert query.
|
7
|
+
#
|
8
|
+
# Most of the time, you do not need to instanciate it yourself.
|
5
9
|
class Query
|
10
|
+
# A conflict close inside a query.
|
11
|
+
#
|
12
|
+
# You never need to instanciate it yourself. Instead, use `Query#on_conflict`.
|
6
13
|
class OnConflict
|
14
|
+
# Create an ON CONFLICT clause
|
15
|
+
#
|
16
|
+
# @param query [Query] the query.
|
17
|
+
# @param column [String | Symbol] the column to watch for conflicts.
|
7
18
|
def initialize(query, column)
|
8
19
|
@query = query
|
9
20
|
@column = column.to_sym
|
10
21
|
end
|
11
22
|
|
23
|
+
# Ignore conflicting rows.
|
24
|
+
#
|
25
|
+
# @return [Query] the original query.
|
12
26
|
def do_nothing
|
13
27
|
@query.on_conflict_sql(::MultiInsert::QueryBuilder.on_conflict_do_nothing(@column))
|
14
28
|
end
|
15
29
|
|
30
|
+
# Update the conflicting rows according to user-supplied rules.
|
31
|
+
#
|
32
|
+
# The rules can be:
|
33
|
+
# - A single symbol or string denoting a column name. In this case, the matching column will be updated.
|
34
|
+
# - An array of strings or symbols. In this case, the matching columns will be updated.
|
35
|
+
# - An hash of values (Integers or Strings) or the symbol `:excluded`. The matching columns will be updated
|
36
|
+
# to the supplied values, except when the value is `:excluded`. In that case, the matching columns will be set
|
37
|
+
# to the value to be inserted.
|
38
|
+
#
|
39
|
+
# @param values [String | Symbol | Array<String | Symbol> | Hash<String | Symbol => String | Number | Boolean>] The user specified rules.
|
40
|
+
# @return [Query] The original query.
|
16
41
|
def do_update(values)
|
17
42
|
@query.on_conflict_sql(::MultiInsert::QueryBuilder.on_conflict_do_update(@column, values, @query.opts))
|
18
43
|
end
|
@@ -20,41 +45,80 @@ module MultiInsert
|
|
20
45
|
|
21
46
|
attr_reader :opts
|
22
47
|
|
48
|
+
# Create an insert query against the specified table and columns, with the specified values.
|
49
|
+
# The following options are supported:
|
50
|
+
# - time (true) Whether to insert created_at and updated_at.
|
51
|
+
#
|
52
|
+
# @param table [String | Symbol] The table to be used for insertion.
|
53
|
+
# @param columns [Array<String | Symbol>] The columns to be inserted.
|
54
|
+
# @param values [Array<Array<String | Number | Boolean>>] The values to be inserted.
|
55
|
+
# @param opts [Hash<Object>] Options.
|
23
56
|
def initialize(table, columns, values, opts = {})
|
24
57
|
@table = table.to_sym
|
25
58
|
@opts = opts
|
26
59
|
@sql_insert = ::MultiInsert::QueryBuilder.insert(table, columns, values, opts)
|
27
60
|
end
|
28
61
|
|
62
|
+
# Add a returning clause to the query.
|
63
|
+
#
|
64
|
+
# @param columns [Array<Symbol | String>] The columns to return.
|
65
|
+
# @return [Query] self.
|
29
66
|
def returning(columns)
|
30
67
|
@sql_returning = ::MultiInsert::QueryBuilder.returning(columns)
|
31
68
|
@returning_flat = false
|
32
69
|
self
|
33
70
|
end
|
34
71
|
|
72
|
+
# Add a returning clause to the query, returning IDs.
|
73
|
+
#
|
74
|
+
# The IDs will be returned as a flat array.
|
75
|
+
# @return [Query] self
|
35
76
|
def returning_id
|
36
77
|
@sql_returning = ::MultiInsert::QueryBuilder.returning([:id])
|
37
78
|
@returning_flat = true
|
38
79
|
self
|
39
80
|
end
|
40
81
|
|
82
|
+
# Begin a conflict clause.
|
83
|
+
#
|
84
|
+
# @param column [String | Symbol] The column to watch for conflicts.
|
85
|
+
# @return [Query::OnConflict] A conflict clause.
|
41
86
|
def on_conflict(column)
|
42
87
|
::MultiInsert::Query::OnConflict.new(self, column)
|
43
88
|
end
|
44
89
|
|
90
|
+
# Handle a conflict with raw SQL
|
91
|
+
#
|
92
|
+
# You should probably use the friendly helper method instead.
|
93
|
+
# @param sql [String] An SQL expression starting with "ON CONFLICT".
|
94
|
+
# @return [Query] self.
|
45
95
|
def on_conflict_sql(sql)
|
46
96
|
@sql_on_conflict = sql
|
47
97
|
self
|
48
98
|
end
|
49
99
|
|
100
|
+
# Convert the query to raw SQL.
|
101
|
+
#
|
102
|
+
# @return [String] An SQL query.
|
50
103
|
def to_sql
|
51
104
|
[@sql_insert, @sql_on_conflict, @sql_returning].reject(&:nil?).join(' ')
|
52
105
|
end
|
53
106
|
|
107
|
+
# Equivalent to `to_sql`.
|
108
|
+
#
|
109
|
+
# @return [String] An SQL query.
|
54
110
|
def to_s
|
55
111
|
to_sql
|
56
112
|
end
|
57
113
|
|
114
|
+
# Execute the query, and return eventual results.
|
115
|
+
#
|
116
|
+
# Result may be:
|
117
|
+
# - Nil if no returning clause was present.
|
118
|
+
# - An array of IDs if the returning_id helper was called.
|
119
|
+
# - An array of rows otherwise.
|
120
|
+
#
|
121
|
+
# @return [nil | Array<Integer> | Array<Array<String | Number | Boolean>>]
|
58
122
|
def execute
|
59
123
|
result = ActiveRecord::Base.connection.execute(to_sql)
|
60
124
|
if @sql_returning.nil?
|
@@ -53,7 +53,8 @@ module MultiInsert
|
|
53
53
|
now = Time.now.to_s(:db)
|
54
54
|
values[:updated_at] = now
|
55
55
|
end
|
56
|
-
|
56
|
+
arr = []
|
57
|
+
values.each do |key, value|
|
57
58
|
v = nil
|
58
59
|
key = ActiveRecord::Base.connection.quote_column_name(key.to_s)
|
59
60
|
if value == :excluded
|
@@ -61,9 +62,9 @@ module MultiInsert
|
|
61
62
|
else
|
62
63
|
v = ActiveRecord::Base.connection.quote(value)
|
63
64
|
end
|
64
|
-
"#{key} = #{v}"
|
65
|
+
arr << "#{key} = #{v}"
|
65
66
|
end
|
66
|
-
values =
|
67
|
+
values = arr.join(', ')
|
67
68
|
"#{on_conflict(column)} DO UPDATE SET #{values}"
|
68
69
|
end
|
69
70
|
|
data/lib/multi_insert/version.rb
CHANGED