fast_inserter 0.1.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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"