insert_select 0.1.0 → 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/Gemfile +2 -0
- data/Gemfile.lock +5 -1
- data/README.md +18 -2
- data/Rakefile +11 -0
- data/lib/insert_select/active_record.rb +9 -4
- data/lib/insert_select/adapters/mysql_adapter.rb +7 -1
- data/lib/insert_select/adapters/postgresql_adapter.rb +5 -3
- data/lib/insert_select/adapters/sqlite_adapter.rb +12 -1
- data/lib/insert_select/builder.rb +6 -1
- data/lib/insert_select/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d101071399faca09bdda11935c64dd05cd278c5d6f09cb868297bd8a39763050
|
4
|
+
data.tar.gz: 955f3d4f643fc7d63898d6b790e442a58df26494e66893c4bf6f61cfa10d11fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6be590eef3ffd3f4f746acc8334dd21175b1621c4a90a1dff4e8597e7bd6505f3d4b684c16e304fde6f86dd98f67cd80458f28b08fa0c47cb9fe06921caffa0
|
7
|
+
data.tar.gz: 75ec347e6e56e2eb405545c741645e81ac04ba1932a5c00515fa0411aebd3b6fc7c38a5213bf5fcce2c4470fd0f926a596a1deb18f8fb08322936ef243cb7758
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
insert_select (
|
4
|
+
insert_select (1.0.0)
|
5
5
|
activerecord
|
6
6
|
|
7
7
|
GEM
|
@@ -22,6 +22,8 @@ GEM
|
|
22
22
|
i18n (1.14.0)
|
23
23
|
concurrent-ruby (~> 1.0)
|
24
24
|
minitest (5.18.0)
|
25
|
+
mysql2 (0.5.5)
|
26
|
+
pg (1.5.3)
|
25
27
|
rake (13.0.6)
|
26
28
|
rspec (3.12.0)
|
27
29
|
rspec-core (~> 3.12.0)
|
@@ -48,6 +50,8 @@ PLATFORMS
|
|
48
50
|
|
49
51
|
DEPENDENCIES
|
50
52
|
insert_select!
|
53
|
+
mysql2
|
54
|
+
pg
|
51
55
|
rake (~> 13.0)
|
52
56
|
rspec (~> 3.0)
|
53
57
|
sqlite3
|
data/README.md
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
[](https://github.com/a5-stable/insert_select/actions/workflows/ruby.yml)
|
3
3
|

|
4
4
|
|
5
|
-
This is a custom gem that extends ActiveRecord to enable the expression of SQL `INSERT INTO ... SELECT ...` queries in a more convenient way.
|
5
|
+
This is a custom gem that extends ActiveRecord to enable the expression of SQL `INSERT INTO ... SELECT ...` queries in a more convenient way.
|
6
|
+
It allows you to copy data from one table to another based on specified conditions using a simple and expressive syntax.
|
6
7
|
|
7
8
|
SQL example of `INSERT INTO ... SELECT ...`:
|
8
9
|
```
|
@@ -78,8 +79,23 @@ NewUser.insert_select_from(OldUser, returning: [:id])
|
|
78
79
|
|
79
80
|
#=> INSERT INTO "new_users" SELECT "old_users".* FROM "old_users" RETURNING "id"
|
80
81
|
```
|
82
|
+
### bang method
|
83
|
+
In default, any duplicated records are skipped in the `insert_select_from` method.
|
84
|
+
If you want to raise an error when a duplicated record is found, use the bang method.
|
85
|
+
|
86
|
+
Assume that `id` is a primary key.
|
87
|
+
This example does not raise an `ActiveRecord::RecordNotUnique` exception and no record is inserted.
|
88
|
+
```ruby
|
89
|
+
User.insert_select_from(User)
|
90
|
+
```
|
91
|
+
|
92
|
+
This example raises an `ActiveRecord::RecordNotUnique` exception.
|
93
|
+
```ruby
|
94
|
+
User.insert_select_from!(User)
|
95
|
+
|
96
|
+
#=> ActiveRecord::RecordNotUnique (SQLite3::ConstraintException: UNIQUE constraint failed: users.id)
|
97
|
+
```
|
81
98
|
|
82
|
-
Other options, which are enabled in [`insert_all`](https://www.rubydoc.info/github/rails/rails/ActiveRecord%2FPersistence%2FClassMethods:insert_all) should be also supported, but are not yet implemented.
|
83
99
|
|
84
100
|
## Development
|
85
101
|
|
data/Rakefile
CHANGED
@@ -5,4 +5,15 @@ require "rspec/core/rake_task"
|
|
5
5
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
7
7
|
|
8
|
+
namespace :spec do
|
9
|
+
["postgresql", "mysql2", "sqlite3"].each do |adapter|
|
10
|
+
RSpec::Core::RakeTask.new(adapter) do |t|
|
11
|
+
ENV["ADAPTER_NAME"] = adapter
|
12
|
+
ENV["DATABASE_NAME"] = adapter == "sqlite3" ? ":memory:" : "insert_select_test"
|
13
|
+
t.pattern = FileList["spec/*_spec.rb"]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
task spec: ["spec:postgresql", "spec:mysql2", "spec:sqlite3"]
|
8
19
|
task default: :spec
|
@@ -34,7 +34,11 @@ module InsertSelect
|
|
34
34
|
# @return [ActiveRecord::Result] The result of the insert select operation.
|
35
35
|
#
|
36
36
|
def insert_select_from(relation, mapping: {}, returning: nil)
|
37
|
-
InsertSelect::ActiveRecord::InsertSelectFrom.new(self, relation, mapping: mapping, returning: returning).execute
|
37
|
+
InsertSelect::ActiveRecord::InsertSelectFrom.new(self, relation, mapping: mapping, on_duplicate: :skip, returning: returning).execute
|
38
|
+
end
|
39
|
+
|
40
|
+
def insert_select_from!(relation, mapping: {}, returning: nil)
|
41
|
+
InsertSelect::ActiveRecord::InsertSelectFrom.new(self, relation, mapping: mapping, on_duplicate: nil, returning: returning).execute
|
38
42
|
end
|
39
43
|
|
40
44
|
def except(*columns)
|
@@ -44,20 +48,21 @@ module InsertSelect
|
|
44
48
|
end
|
45
49
|
|
46
50
|
class InsertSelectFrom
|
47
|
-
attr_reader :model, :connection, :relation, :adapter, :mapping, :returning
|
51
|
+
attr_reader :model, :connection, :relation, :adapter, :mapping, :returning, :on_duplicate
|
48
52
|
|
49
|
-
def initialize(model, relation, mapping:, returning: nil)
|
53
|
+
def initialize(model, relation, mapping:, on_duplicate:, returning: nil)
|
50
54
|
@model = model
|
51
55
|
@connection = model.connection
|
52
56
|
@relation = relation
|
53
57
|
@adapter = find_adapter(connection)
|
54
58
|
@mapping = mapping
|
55
59
|
@returning = returning
|
60
|
+
@on_duplicate = on_duplicate
|
56
61
|
end
|
57
62
|
|
58
63
|
def execute
|
59
64
|
sql = model.sanitize_sql_array([to_sql, *builder.constant_values])
|
60
|
-
connection.exec_insert_all(sql, "")
|
65
|
+
connection.exec_insert_all(sql, "Bulk Insert")
|
61
66
|
end
|
62
67
|
|
63
68
|
def to_sql
|
@@ -7,10 +7,12 @@ module InsertSelect
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def build_sql(builder)
|
10
|
-
|
11
|
-
sql += " RETURNING #{builder.returning}" if builder.returning
|
10
|
+
stmt = super
|
12
11
|
|
13
|
-
|
12
|
+
stmt << " ON CONFLICT DO NOTHING" if builder.on_duplicate == :skip
|
13
|
+
stmt << " RETURNING #{builder.returning}" if builder.returning?
|
14
|
+
|
15
|
+
stmt
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -7,7 +7,18 @@ module InsertSelect
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def build_sql(builder)
|
10
|
-
super
|
10
|
+
# have to be done before we call super, because super will make relation immutable
|
11
|
+
if builder.on_duplicate == :skip
|
12
|
+
builder.relation.where!("TRUE") if builder.relation.where_clause.blank?
|
13
|
+
end
|
14
|
+
|
15
|
+
stmt = super
|
16
|
+
|
17
|
+
if builder.on_duplicate == :skip
|
18
|
+
stmt << " ON CONFLICT DO NOTHING"
|
19
|
+
end
|
20
|
+
|
21
|
+
stmt
|
11
22
|
end
|
12
23
|
end
|
13
24
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module InsertSelect
|
2
2
|
module ActiveRecord
|
3
3
|
class Builder
|
4
|
-
attr_reader :relation, :mapping, :model, :
|
4
|
+
attr_reader :relation, :mapping, :model,:insert_select_from, :connection, :returning, :on_duplicate
|
5
5
|
|
6
6
|
def initialize(insert_select_from)
|
7
7
|
@insert_select_from = insert_select_from
|
@@ -10,6 +10,7 @@ module InsertSelect
|
|
10
10
|
@mapping = insert_select_from.mapping || {}
|
11
11
|
@model = insert_select_from.model
|
12
12
|
@returning = insert_select_from.returning
|
13
|
+
@on_duplicate = insert_select_from.on_duplicate
|
13
14
|
end
|
14
15
|
|
15
16
|
def mapper
|
@@ -90,6 +91,10 @@ module InsertSelect
|
|
90
91
|
end
|
91
92
|
end
|
92
93
|
|
94
|
+
def returning?
|
95
|
+
@returning.present?
|
96
|
+
end
|
97
|
+
|
93
98
|
private
|
94
99
|
|
95
100
|
def remove_select_values!(column_name)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: insert_select
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- a5-stable
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|