fast_inserter 0.1.6 → 2.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
- SHA1:
3
- metadata.gz: fe09e32230a3dc433d82f2afe7329cfe6388c46d
4
- data.tar.gz: ea29978534d0cb33c67baafa43fbcd1f8d02735a
2
+ SHA256:
3
+ metadata.gz: b34b8efaffa71fa07824869fc4786cfbd075c878ba99c96989846bf0e3a5c377
4
+ data.tar.gz: e688e45fe0316029dab434a56ff1ad5f2c1cdfb7644995d2f4fcc3762ecbf5a8
5
5
  SHA512:
6
- metadata.gz: 03556b9df683ce5c6bce7797af5d6754a001167aeae82bd4edc43b2ed2eb0fc21a23c15f32fb740a1fe884a846660ccebda1cc514dd1c048fc6b619b0470ca61
7
- data.tar.gz: 389035369e1874a8f522a0c5dbd0be6ddc6e9f16dbf6088101021e05def715d5c204dc49dacb278e8405f4a328c72a7739c472bd3698ada9d233140ed826c0a2
6
+ metadata.gz: aa47c991faaf1170779cac718a85a1d89a28b393feae40014296100281d1ecab918dba51ca64733dc8c193ac7784b2fa5866b9a3642f82219c9bf58007427f4d
7
+ data.tar.gz: 73b3b9ec678d4588fac02f9477aac000391b34f31d072194be4690798d541823fcccdfda56ac79b854f089e247d2a33377cfc25707384e75594405419a916022
@@ -0,0 +1,55 @@
1
+ name: Ruby
2
+
3
+ on: push
4
+
5
+ jobs:
6
+ build-and-test-job:
7
+ runs-on: ubuntu-20.04
8
+
9
+ strategy:
10
+ matrix:
11
+ ruby-version: ['2.6.10', '2.7.8', '3.0.6', '3.1.4', '3.2.2', 'ruby-head']
12
+ database: [sqlite, pg, mysql]
13
+
14
+ # Postgres has to be explicitly included. The runner environment already has mysql installed by default.
15
+ services:
16
+ postgres:
17
+ # Pin to this commit: version 14.0
18
+ image: postgres@sha256:2b8a60d4ae4b3cf9dc5ae823700f699fdabdb0d03901dd480c9a410ca72c4571
19
+ env:
20
+ # Password is required. Postgres won't start without it.
21
+ POSTGRES_PASSWORD: postgres_password
22
+ ports:
23
+ - 5432:5432
24
+ options: >-
25
+ --health-cmd pg_isready
26
+ --health-interval 10s
27
+ --health-timeout 5s
28
+ --health-retries 5
29
+
30
+ env:
31
+ # CAUTION - the DB env var is also used by the test setup code. Don't change the name of it!
32
+ DB: ${{ matrix.database }}
33
+ RV: ${{ matrix.ruby-version }}
34
+ PGPASSWORD: postgres_password
35
+
36
+ steps:
37
+ - name: Init
38
+ run: echo "Using Ruby $RV and '$DB' as the database."
39
+ - name: Checkout
40
+ # Pin to this commit: v2
41
+ uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
42
+ - name: Set up Database
43
+ run: |
44
+ if [ "$DB" = "pg" ]; then psql -h localhost -c 'DROP DATABASE IF EXISTS fast_inserter;' -U postgres; fi
45
+ if [ "$DB" = "pg" ]; then psql -h localhost -c 'create database fast_inserter;' -U postgres; fi
46
+ if [ "$DB" = "mysql" ]; then sudo systemctl start mysql.service; fi
47
+ if [ "$DB" = "mysql" ]; then mysql -e 'create database IF NOT EXISTS fast_inserter;' -uroot -proot; fi
48
+ - name: Set up Ruby
49
+ uses: ruby/setup-ruby@v1
50
+ with:
51
+ ruby-version: ${{ matrix.ruby-version }}
52
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
53
+ - name: Run tests
54
+ # The test setup code reads the DB env var to determine which database to use.
55
+ run: bundle exec rake
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.3.0
1
+ 3.0.6
data/CHANGELOG.md CHANGED
@@ -1,4 +1,24 @@
1
- ## Unreleased ##
1
+ ## 2.0.0 (April 20, 2023) ##
2
+
3
+ * Drop Ruby version 2.4 and 2.5 support
4
+ * Add Ruby versions 3.0.6, 3.1.4, 3.2.2
5
+ * Update development Ruby version to 3.0.6
6
+ * Update type casting in preparation for rails 7
7
+ * Account for MySQL type casting in ActiveRecord 7
8
+
9
+ *Amy Lin, Tim Kelly*
10
+
11
+ ## 1.0.0.pre (January 7, 2019) ##
12
+
13
+ * Use database IN clause when checking for existing records.
14
+
15
+ *Jordon Dornbos*
16
+
17
+ ## 0.1.6 (July 3, 2018) ##
18
+
19
+ * Fix check_for_existing with multiple variable columns.
20
+
21
+ *Josh Warfield*
2
22
 
3
23
  * Remove support for Ruby 2.2. Add support for Ruby 2.4 and 2.5.
4
24
 
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # FastInserter
2
2
 
3
+ [![Build Status](https://github.com/joinhandshake/fast_inserter/actions/workflows/ruby.yml/badge.svg)](https://github.com/joinhandshake/fast_inserter/actions)
3
4
  [![Gem Version](https://badge.fury.io/rb/fast_inserter.svg)](https://badge.fury.io/rb/fast_inserter)
4
- [![Build Status](https://travis-ci.org/joinhandshake/fast_inserter.svg?branch=master)](https://travis-ci.org/joinhandshake/fast_inserter)
5
5
 
6
6
  Use raw SQL to insert database records in bulk, fast. Supports uniqueness constraints, timestamps, and checking for existing records.
7
7
 
@@ -51,9 +51,9 @@ params = {
51
51
  options: {
52
52
  timestamps: true,
53
53
  unique: true,
54
- check_for_existing: true,
55
- group_size: 2_000
54
+ check_for_existing: true
56
55
  },
56
+ group_size: 2_000,
57
57
  variable_column: 'user_id',
58
58
  values: user_ids
59
59
  }
@@ -89,7 +89,7 @@ Queries the table for any values which already exist and removes them from the v
89
89
 
90
90
  ### group_size
91
91
 
92
- Insertions will be broken up into batches. This specifies the number of records you want to insert per batch. Default is 2,000.
92
+ Insertions will be broken up into batches. This specifies the number of records you want to insert per batch. Default is 1,000.
93
93
 
94
94
  ### variable_column
95
95
 
@@ -21,16 +21,16 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_runtime_dependency 'activerecord', '>= 4.1.0'
23
23
 
24
- spec.required_ruby_version = ">= 2.2.0"
24
+ spec.required_ruby_version = ">= 2.3.8"
25
25
 
26
26
  spec.add_development_dependency "bundler"
27
- spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rake"
28
28
  spec.add_development_dependency "rspec"
29
29
  spec.add_development_dependency "database_cleaner"
30
30
 
31
31
  case ENV['DB']
32
32
  when "mysql"; spec.add_development_dependency "mysql2"
33
- when "sqlite"; spec.add_development_dependency "sqlite3"
33
+ when "sqlite"; spec.add_development_dependency "sqlite3", ">= 1.4"
34
34
  when "pg"; spec.add_development_dependency "pg"
35
35
  else spec.add_development_dependency "sqlite3" # Default
36
36
  end
@@ -1,3 +1,5 @@
1
+ require 'enumerator'
2
+
1
3
  # Highly based off of https://github.com/sportngin/m2m_fast_insert
2
4
  # Unfortunately, that gem was not up to date for rails 4.
3
5
  #
@@ -18,8 +20,7 @@
18
20
  # options: {
19
21
  # timestamps: true,
20
22
  # unique: true,
21
- # check_for_existing: true,
22
- # group_size: 1_000
23
+ # check_for_existing: true
23
24
  # },
24
25
  # variable_column: 'user_id',
25
26
  # values: user_ids
@@ -39,11 +40,11 @@
39
40
  # A hash representing additional column values to set that you don't want
40
41
  # to include in uniqueness checks or other pre-insertion operations.
41
42
  # group_size: Integer
42
- # The number of items you want to insert per batch of records. Default 10_000.
43
+ # The number of items you want to insert per batch of records. Defaults to 1_000.
43
44
  #
44
45
  module FastInserter
45
46
  class Base
46
- DEFAULT_GROUP_SIZE = 2_000
47
+ DEFAULT_GROUP_SIZE = 1_000
47
48
 
48
49
  def initialize(params)
49
50
  @table_name = params[:table]
@@ -58,7 +59,7 @@ module FastInserter
58
59
  all_values = params[:values].map { |value| Array(value) }
59
60
  all_values.uniq! if @options[:unique]
60
61
  group_size = Integer(params[:group_size] || ENV['FAST_INSERTER_GROUP_SIZE'] || DEFAULT_GROUP_SIZE)
61
- @value_groups = all_values.in_groups_of(group_size, false)
62
+ @value_groups = all_values.each_slice(group_size).to_a
62
63
  end
63
64
 
64
65
  # Iterates through the value groups (which is all values in groups of smaller sizes)
@@ -92,34 +93,70 @@ module FastInserter
92
93
  end
93
94
  end
94
95
 
96
+ def existing_values_sql(group_of_values)
97
+ sql = "SELECT #{@variable_columns.join(', ')} FROM #{@table_name} WHERE #{values_hash_to_sql(@static_columns)}"
98
+
99
+ if @variable_columns.length > 1
100
+ group_of_values_sql = group_of_values.map do |group|
101
+ values_hash = variable_column_values_to_hash(group)
102
+ "(#{values_hash_to_sql(values_hash)})"
103
+ end.join(' OR ')
104
+
105
+ sql += " AND (#{group_of_values_sql})"
106
+ else
107
+ values_to_check = ActiveRecord::Base.send(:sanitize_sql_array, ['?', group_of_values.flatten])
108
+ sql += " AND #{@variable_columns.first} IN (#{values_to_check})"
109
+ end
110
+
111
+ sql
112
+ end
113
+
95
114
  # Queries for the existing values for a given group of values
96
115
  def existing_values(group_of_values)
97
- sql = "SELECT #{@variable_columns.join(', ')} FROM #{@table_name} WHERE #{existing_values_static_columns}"
116
+ sql = existing_values_sql(group_of_values)
98
117
 
99
118
  # NOTE: There are more elegant ways to get this field out of the resultset, but each database adaptor returns a different type
100
119
  # of result from 'execute(sql)'. Potential classes for 'result' is Array (sqlite), Mysql2::Result (mysql2), PG::Result (pg). Each
101
120
  # result can be enumerated into a list of arrays (mysql) or list of hashes (sqlite, pg)
102
121
  results = ActiveRecord::Base.connection.execute(sql)
103
- existing_values = stringify_values(results)
104
-
105
- # Rather than a giant IN query in the sql statement (which can be bad for database performance),
106
- # do the filtering of relevant values here in a ruby select.
107
- group_of_values_strings = stringify_values(group_of_values)
108
- existing_values & group_of_values_strings
122
+ stringify_values(results)
109
123
  end
110
124
 
111
125
  def stringify_values(results)
112
126
  results.to_a.map do |result|
113
127
  if result.is_a?(Hash)
114
- @variable_columns.map { |col| ActiveRecord::Base.connection.type_cast(result[col], column_definitions[col]) }
128
+ @variable_columns.map { |col| type_cast_column(result[col], column_definitions[col]) }
115
129
  elsif result.is_a?(Array)
116
- result.map.with_index { |val, i| ActiveRecord::Base.connection.type_cast(val, column_definitions[@variable_columns[i]]) }
130
+ result.map.with_index { |val, i| type_cast_column(val, column_definitions[@variable_columns[i]]) }
117
131
  end
118
132
  end
119
133
  end
120
134
 
121
- def existing_values_static_columns
122
- @static_columns.map do |key, value|
135
+ # Passing a column to the method type_cast is deprecated
136
+ # and will be removed in Rails 7. For now, we can manually
137
+ # call lookup_cast_type_from_column and serialize our
138
+ # values with the returned type.
139
+ def type_cast_column(value, column = nil)
140
+ if column
141
+ type = ActiveRecord::Base.connection.lookup_cast_type_from_column(column)
142
+ value = type.serialize(value)
143
+ end
144
+
145
+ ActiveRecord::Base.connection.type_cast(value)
146
+ end
147
+
148
+ def variable_column_values_to_hash(values)
149
+ hash = {}
150
+
151
+ @variable_columns.each_with_index do |variable_column, index|
152
+ hash[variable_column] = values[index]
153
+ end
154
+
155
+ hash
156
+ end
157
+
158
+ def values_hash_to_sql(values)
159
+ values.map do |key, value|
123
160
  if value.nil?
124
161
  "#{key} IS NULL"
125
162
  else
@@ -1,3 +1,3 @@
1
1
  module FastInserter
2
- VERSION = "0.1.6"
2
+ VERSION = '2.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_inserter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Ringwelski
@@ -9,10 +9,10 @@ authors:
9
9
  - Jordon Dornbos
10
10
  - Matt Hickman
11
11
  - Josh Warfield
12
- autorequire:
12
+ autorequire:
13
13
  bindir: exe
14
14
  cert_chain: []
15
- date: 2018-07-03 00:00:00.000000000 Z
15
+ date: 2023-04-25 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: activerecord
@@ -46,16 +46,16 @@ dependencies:
46
46
  name: rake
47
47
  requirement: !ruby/object:Gem::Requirement
48
48
  requirements:
49
- - - "~>"
49
+ - - ">="
50
50
  - !ruby/object:Gem::Version
51
- version: '10.0'
51
+ version: '0'
52
52
  type: :development
53
53
  prerelease: false
54
54
  version_requirements: !ruby/object:Gem::Requirement
55
55
  requirements:
56
- - - "~>"
56
+ - - ">="
57
57
  - !ruby/object:Gem::Version
58
- version: '10.0'
58
+ version: '0'
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: rspec
61
61
  requirement: !ruby/object:Gem::Requirement
@@ -110,10 +110,10 @@ executables: []
110
110
  extensions: []
111
111
  extra_rdoc_files: []
112
112
  files:
113
+ - ".github/workflows/ruby.yml"
113
114
  - ".gitignore"
114
115
  - ".rspec"
115
116
  - ".ruby-version"
116
- - ".travis.yml"
117
117
  - CHANGELOG.md
118
118
  - Gemfile
119
119
  - LICENSE.txt
@@ -129,7 +129,7 @@ homepage: https://github.com/strydercorp/fast_inserter
129
129
  licenses:
130
130
  - MIT
131
131
  metadata: {}
132
- post_install_message:
132
+ post_install_message:
133
133
  rdoc_options: []
134
134
  require_paths:
135
135
  - lib
@@ -137,16 +137,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
137
137
  requirements:
138
138
  - - ">="
139
139
  - !ruby/object:Gem::Version
140
- version: 2.2.0
140
+ version: 2.3.8
141
141
  required_rubygems_version: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
144
144
  - !ruby/object:Gem::Version
145
145
  version: '0'
146
146
  requirements: []
147
- rubyforge_project:
148
- rubygems_version: 2.5.1
149
- signing_key:
147
+ rubygems_version: 3.2.33
148
+ signing_key:
150
149
  specification_version: 4
151
150
  summary: Quickly insert database records in bulk
152
151
  test_files: []
data/.travis.yml DELETED
@@ -1,19 +0,0 @@
1
- language: ruby
2
- sudo: required
3
- notifications:
4
- email: false
5
- rvm:
6
- - 2.3.0
7
- - 2.4.4
8
- - 2.5.1
9
- - ruby-head
10
- env:
11
- matrix:
12
- - DB=pg
13
- - DB=mysql
14
- - DB=sqlite
15
- before_script:
16
- # PG and mysql is simpler.
17
- - sh -c "if [ '$DB' = 'pg' ]; then psql -c 'DROP DATABASE IF EXISTS fast_inserter;' -U postgres; fi"
18
- - sh -c "if [ '$DB' = 'pg' ]; then psql -c 'create database fast_inserter;' -U postgres; fi"
19
- - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS fast_inserter;'; fi"