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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ed398397217cbd7d7a636948b89a3cfb32bbfa6c9288619e249e014f895febc
4
- data.tar.gz: 015b72e911c1183215858260e3aa96dc6ec47000f2221ec7c7147929deb94167
3
+ metadata.gz: d101071399faca09bdda11935c64dd05cd278c5d6f09cb868297bd8a39763050
4
+ data.tar.gz: 955f3d4f643fc7d63898d6b790e442a58df26494e66893c4bf6f61cfa10d11fb
5
5
  SHA512:
6
- metadata.gz: 9b5ec0d676bb246917b348e656bcb20b89ea4fdb509ae834dc1f32704f2c8faa97a8ce394b6629deb26001f06cdc59550c01c78f49febbb94e936cc1ec88d9a1
7
- data.tar.gz: 5179a2af5b2b62670f42f1b1fec76f9c38cfc2c9d025e82de60b4d5f6e3a16df27096992896533abf25759b8423dc68afce0939e09b1486392022e74168b50fe
6
+ metadata.gz: e6be590eef3ffd3f4f746acc8334dd21175b1621c4a90a1dff4e8597e7bd6505f3d4b684c16e304fde6f86dd98f67cd80458f28b08fa0c47cb9fe06921caffa0
7
+ data.tar.gz: 75ec347e6e56e2eb405545c741645e81ac04ba1932a5c00515fa0411aebd3b6fc7c38a5213bf5fcce2c4470fd0f926a596a1deb18f8fb08322936ef243cb7758
data/Gemfile CHANGED
@@ -9,3 +9,5 @@ gem "rake", "~> 13.0"
9
9
 
10
10
  gem "rspec", "~> 3.0"
11
11
  gem "sqlite3"
12
+ gem "mysql2"
13
+ gem "pg"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- insert_select (0.1.0)
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
  [![Ruby](https://github.com/a5-stable/insert_select/actions/workflows/ruby.yml/badge.svg)](https://github.com/a5-stable/insert_select/actions/workflows/ruby.yml)
3
3
  ![Code Climate](https://codeclimate.com/github/a5-stable/insert_select.png)
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. It allows you to copy data from one table to another based on specified conditions using a simple and expressive syntax.
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,7 +7,13 @@ module InsertSelect
7
7
  end
8
8
 
9
9
  def build_sql(builder)
10
- super
10
+ stmt = super
11
+
12
+ if builder.on_duplicate == :skip
13
+ stmt << " ON DUPLICATE KEY UPDATE `id`= VALUES(`id`) "
14
+ end
15
+
16
+ stmt
11
17
  end
12
18
  end
13
19
  end
@@ -7,10 +7,12 @@ module InsertSelect
7
7
  end
8
8
 
9
9
  def build_sql(builder)
10
- sql = super
11
- sql += " RETURNING #{builder.returning}" if builder.returning
10
+ stmt = super
12
11
 
13
- sql
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, :returning, :insert_select_from, :connection
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module InsertSelect
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.0"
5
5
  end
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: 0.1.0
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-06-22 00:00:00.000000000 Z
11
+ date: 2023-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord