better_batch 0.1.0 → 1.0.2

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: 7cc3b9f2cc9e37f55a2c78f05c4c6e5b97a9d08030b0fc791d68286c76301a3a
4
- data.tar.gz: e29d0257f1656ff93375ddbd6b3928256a90f9a5dc3d499fd7360acc626eac24
3
+ metadata.gz: 13c31343ab529bbd8df1009f601778fb504897bdfdb8b4d77f7165bad88620a1
4
+ data.tar.gz: 571f51a6631cdac4d47aca08dba3964b281b8831fb5ec7820bcd97c669814116
5
5
  SHA512:
6
- metadata.gz: a1dfea45b6940be0add55d6f4f7567dbc3c57f30e8db76d22032b12190050a26aab7b59dc1b18e91f0455ed1300850079a3fd249af3857d269366f774848f749
7
- data.tar.gz: cefa7b0d4d121ed2c7bfcc74dcaa0dd77313076a3667ad07cade336c8a9bf10af53b868995112b8b9c9148bc6f4708571b97085106eaa97442269f531acc3b67
6
+ metadata.gz: 38ccffb6de7831944d5c2eb7de2ea93f7ea56c7a9b392ee74fc148d4378795a3f33fdcb55e9e0f3912e7618fa6ecd26a561959c60a1d2fd4e1fd900eb59bd1f8
7
+ data.tar.gz: e2c9efca1a99bb78aabe321a5f5b5eb322743e5463e8925574512ebc2855a18572b3008570699b396ee99d6569e6ee2670fe9dd7cb5c38d41382e96c3e8145b1
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ plugins:
3
3
  - rubocop-rspec
4
4
  AllCops:
5
5
  NewCops: enable
6
- TargetRubyVersion: 3.1
6
+ TargetRubyVersion: 3.2
7
7
 
8
8
  RSpec/ContextWording:
9
9
  Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.2
data/CHANGELOG.md CHANGED
@@ -1,4 +1,14 @@
1
- ## [Unreleased]
1
+ ## [1.0.2] - 2025-04-15
2
+
3
+ - Test version to excercise deployment updates
4
+
5
+ ## [1.0.1] - 2025-04-15
6
+
7
+ - Fix dependency definition
8
+
9
+ ## [1.0.0] - 2025-04-15
10
+
11
+ - Initial feature set
2
12
 
3
13
  ## [0.1.0] - 2025-04-04
4
14
 
data/README.md CHANGED
@@ -11,30 +11,37 @@ For now, only Postgres is supported.
11
11
  In your Gemfile:
12
12
  ```ruby
13
13
  source 'https://rubygems.org'
14
- gem 'lazier_data'
14
+ gem 'better_batch'
15
15
  ```
16
16
  Then:
17
17
  `bundle`
18
18
 
19
19
  ## Usage
20
20
 
21
+ If you're using ActiveRecord, you'll want to use [better_batch-active_record](https://github.com/th7/better_batch-active_record).
22
+
21
23
  ```ruby
22
24
  table_name = :the_table
23
25
  primary_key = :the_primary_key
24
- columns = %i[column_a column_b column_c]
26
+ input_columns = %i[column_a column_b column_c]
25
27
  column_types = {
26
28
  column_a: 'character varying(200)',
27
29
  column_b: 'bigint',
28
30
  column_c: 'text'
29
31
  }
30
32
  unique_columns = %i[column_b column_c]
31
-
33
+ now_on_insert = %i[created_at updated_at]
34
+ now_on_update = %i[updated_at]
35
+ returning = %i[id]
32
36
  query = BetterBatch::Query.new(
33
37
  table_name:,
34
38
  primary_key:,
35
- columns:,
39
+ input_columns:,
36
40
  column_types:,
37
- unique_columns:
41
+ unique_columns:,
42
+ now_on_insert:,
43
+ now_on_update:,
44
+ returning:
38
45
  )
39
46
 
40
47
  data = [
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'English'
3
4
  require 'bundler/gem_tasks'
4
5
  require 'rspec/core/rake_task'
5
6
 
@@ -10,3 +11,81 @@ require 'rubocop/rake_task'
10
11
  RuboCop::RakeTask.new
11
12
 
12
13
  task default: %i[spec rubocop]
14
+
15
+ module Tasks
16
+ BUILD_FILENAME = 'better_batch.gem'
17
+
18
+ class << self
19
+ include Rake::DSL
20
+
21
+ def install
22
+ install_release_if
23
+ end
24
+
25
+ private
26
+
27
+ def install_release_if # rubocop:disable Metrics/MethodLength
28
+ namespace :release do
29
+ desc 'release if current version is later than last published version'
30
+ task if: :default do
31
+ assert_correct_branch!
32
+ if current_version > published_version
33
+ assert_ci!
34
+ # from bundler, asserts working directory is clean
35
+ Rake::Task['release'].invoke
36
+ end
37
+ assert_version_sane!
38
+ end
39
+ end
40
+ end
41
+
42
+ def published_version
43
+ @published_version ||= build_published_version
44
+ end
45
+
46
+ def build_published_version
47
+ raw = shr('gem search --remote --exact better_batch')
48
+ Gem::Version.new(raw.split('(').last.sub(')', ''))
49
+ end
50
+
51
+ def current_version
52
+ @current_version ||= Gem::Version.new(BetterBatch::VERSION)
53
+ end
54
+
55
+ def assert_version_sane!
56
+ return unless current_version < published_version
57
+
58
+ raise "BetterBatch::VERSION (#{current_version}) " \
59
+ "is less than the current published (#{published_version}). " \
60
+ 'Was it edited incorrectly?'
61
+ end
62
+
63
+ def current_branch
64
+ @current_branch ||= shr('git rev-parse --abbrev-ref HEAD').chomp
65
+ end
66
+
67
+ def default_branch
68
+ @default_branch ||= shr('git remote show origin').match(/HEAD branch: (\S+)$/)[1]
69
+ end
70
+
71
+ def assert_correct_branch!
72
+ return unless current_branch != default_branch
73
+
74
+ raise "On branch (#{current_branch}) instead of default #{default_branch}."
75
+ end
76
+
77
+ def assert_ci!
78
+ raise 'Not in CI.' unless ENV['CI'] == 'true'
79
+ end
80
+
81
+ def shr(cmd)
82
+ puts cmd
83
+ result = `#{cmd}`
84
+ raise cmd unless $CHILD_STATUS == 0
85
+
86
+ result
87
+ end
88
+ end
89
+ end
90
+
91
+ Tasks.install
Binary file
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterBatch
4
+ Inputs = Struct.new(
5
+ :table_name,
6
+ :primary_key,
7
+ :input_columns,
8
+ :column_types,
9
+ :unique_columns,
10
+ :now_on_insert,
11
+ :now_on_update,
12
+ :returning,
13
+ keyword_init: true
14
+ )
15
+
16
+ # this strange (to me) setup avoids method redefinition warnings
17
+ module InstanceOverrides
18
+ def returning
19
+ case self[:returning]
20
+ when nil
21
+ []
22
+ when '*', ['*']
23
+ column_types.keys
24
+ else
25
+ self[:returning]
26
+ end
27
+ end
28
+
29
+ def now_on_insert
30
+ return Array(self[:now_on_insert]) unless self[:now_on_insert].is_a?(Array)
31
+
32
+ self[:now_on_insert]
33
+ end
34
+
35
+ def now_on_update
36
+ return Array(self[:now_on_update]) unless self[:now_on_update].is_a?(Array)
37
+
38
+ self[:now_on_update]
39
+ end
40
+ end
41
+
42
+ class Inputs
43
+ prepend InstanceOverrides
44
+ end
45
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module BetterBatch
6
+ class Inserted
7
+ extend Forwardable
8
+ def_delegators :@inputs, :table_name, :input_columns, :unique_columns, :primary_key, :now_on_insert, :returning
9
+
10
+ TEMPLATE = <<~SQL
11
+ insert into %<table_name>s (%<input_columns_sql>s)
12
+ select distinct on (%<query_columns_sql>s)
13
+ %<select_columns_sql>s
14
+ from selected
15
+ where %<primary_key>s is null
16
+ %<returning_sql>s
17
+ SQL
18
+
19
+ def initialize(inputs)
20
+ @inputs = inputs
21
+ end
22
+
23
+ def sql
24
+ format(TEMPLATE, table_name:, primary_key:, input_columns_sql:, query_columns_sql:, select_columns_sql:,
25
+ returning_sql:)
26
+ end
27
+
28
+ private
29
+
30
+ def input_columns_sql
31
+ @input_columns_sql ||= (input_columns + now_on_insert).join(', ')
32
+ end
33
+
34
+ def select_columns_sql
35
+ @select_columns_sql ||= (input_columns + now_as).join(', ')
36
+ end
37
+
38
+ def query_columns_sql
39
+ @query_columns_sql ||= unique_columns.join(', ')
40
+ end
41
+
42
+ def returning_sql
43
+ @returning_sql ||= build_returning_sql
44
+ end
45
+
46
+ def build_returning_sql
47
+ return '' if returning.empty?
48
+
49
+ "returning #{((returning - input_columns) + unique_columns).join(', ')}"
50
+ end
51
+
52
+ def now_as
53
+ @now_as ||= now_on_insert.map { |c| "now() as #{c}" }
54
+ end
55
+ end
56
+ end
@@ -1,124 +1,157 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'forwardable'
4
+
5
+ require 'anbt-sql-formatter/formatter'
6
+
7
+ require 'better_batch'
8
+ require 'better_batch/inputs'
9
+ require 'better_batch/selected'
10
+ require 'better_batch/inserted'
11
+ require 'better_batch/updated'
12
+
3
13
  module BetterBatch
4
14
  class Query # rubocop:disable Metrics/ClassLength
15
+ extend Forwardable
16
+ def_delegators :@inputs, :table_name, :input_columns, :column_types, :unique_columns, :primary_key, :now_on_insert,
17
+ :now_on_update, :returning
18
+
5
19
  SELECT_TEMPLATE = <<~SQL
6
- select id from (%<selected_inner>s)
7
- order by ordinal
20
+ select %<selected_returning>s
21
+ from (%<selected_sql>s) selected
22
+ order by %<ordinal>s
8
23
  SQL
9
24
 
10
25
  UPSERT_TEMPLATE = <<~SQL
11
- with selected as (
12
- %<selected_inner>s
13
- )
14
- ,inserted as (
15
- %<inserted_inner>s
16
- )
17
- %<updated_clause>s
18
- select coalesce(selected.id, inserted.id) as id
19
- from selected left join inserted using(%<query_columns_text>s)
20
- order by selected.ordinal
26
+ with %<with_sql>s
27
+ select %<upsert_returning>s
28
+ from selected
29
+ %<join_sql>s
30
+ order by selected.%<ordinal>s
21
31
  SQL
22
32
 
23
- SELECTED_INNER_TEMPLATE = <<~SQL
24
- select %<table_name>s.%<primary_key>s as id, %<input_columns_text>s, ordinal
25
- from rows from (
26
- jsonb_to_recordset($1)
27
- as (%<typed_columns_text>s)
28
- ) with ordinality as input(%<columns_text>s, ordinal)
29
- left join %<table_name>s
30
- using(%<query_columns_text>s)
33
+ UPSERT_NO_RETURN_TEMPLATE = <<~SQL
34
+ with %<with_sql>s
35
+ select true as done
31
36
  SQL
32
37
 
33
- INSERTED_INNER_TEMPLATE = <<~SQL
34
- insert into %<table_name>s (%<columns_text>s, created_at, updated_at)
35
- select distinct on (%<query_columns_text>s)
36
- %<columns_text>s, now() as created_at, now() as updated_at
37
- from selected
38
- where id is null
39
- returning id, %<query_columns_text>s
40
- SQL
38
+ def initialize(**)
39
+ @inputs = Inputs.new(**)
40
+ end
41
41
 
42
- UPDATED_INNER_TEMPLATE = <<~SQL
43
- update %<table_name>s
44
- set %<update_columns_text>s, updated_at = now()
45
- from selected where %<table_name>s.id = selected.id
46
- SQL
42
+ def select
43
+ raise Error, 'Select query returning nothing is invalid.' if returning.empty?
47
44
 
48
- def initialize(table_name:, primary_key:, columns:, column_types:, unique_columns:)
49
- @table_name = table_name
50
- @primary_key = primary_key
51
- @columns = columns
52
- @column_types = column_types
53
- @unique_columns = unique_columns
45
+ format(SELECT_TEMPLATE, selected_returning:, selected_sql: selected.sql, ordinal: Selected::ORDINAL)
54
46
  end
55
47
 
56
- def select
57
- format(SELECT_TEMPLATE, selected_inner:)
48
+ def select_formatted
49
+ format_sql(select)
58
50
  end
59
51
 
60
52
  def upsert
61
- params = { selected_inner:, inserted_inner:, updated_clause:, query_columns_text: }
62
- format(UPSERT_TEMPLATE, **params)
53
+ if returning.empty?
54
+ upsert_no_return
55
+ else
56
+ upsert_normal
57
+ end
58
+ end
59
+
60
+ def upsert_formatted
61
+ format_sql(upsert)
62
+ end
63
+
64
+ def inspect
65
+ @inputs.inspect
63
66
  end
64
67
 
65
68
  private
66
69
 
67
- attr_reader :table_name, :columns, :column_types, :unique_columns, :primary_key
70
+ def upsert_no_return
71
+ format(UPSERT_NO_RETURN_TEMPLATE, with_sql:)
72
+ end
73
+
74
+ def upsert_normal
75
+ params = { with_sql:, upsert_returning:, join_sql:, ordinal: Selected::ORDINAL }
76
+ format(UPSERT_TEMPLATE, **params)
77
+ end
68
78
 
69
- def selected_inner
70
- @selected_inner ||= build_selected_inner
79
+ def with_sql
80
+ @with_sql ||= build_with_sql
71
81
  end
72
82
 
73
- def build_selected_inner
74
- params = { table_name:, primary_key:, input_columns_text:, typed_columns_text:, columns_text:,
75
- query_columns_text: }
76
- format(SELECTED_INNER_TEMPLATE, **params)
83
+ def build_with_sql
84
+ with_parts.map { |name, sql| "#{name} as (#{sql})" }.join(', ')
77
85
  end
78
86
 
79
- def inserted_inner
80
- @inserted_inner ||= build_inserted_inner
87
+ def with_parts
88
+ if update_columns.empty?
89
+ { selected: selected.sql, inserted: inserted.sql }
90
+ else
91
+ { selected: selected.sql, inserted: inserted.sql, updated: updated.sql }
92
+ end
81
93
  end
82
94
 
83
- def build_inserted_inner
84
- format(INSERTED_INNER_TEMPLATE, table_name:, columns_text:, query_columns_text:)
95
+ def selected
96
+ @selected ||= Selected.new(@inputs)
85
97
  end
86
98
 
87
- def updated_clause
88
- @updated_clause ||= build_updated_clause
99
+ def inserted
100
+ @inserted ||= Inserted.new(@inputs)
89
101
  end
90
102
 
91
- def build_updated_clause
92
- if update_columns.empty?
93
- "\n"
103
+ def updated
104
+ @updated ||= Updated.new(@inputs)
105
+ end
106
+
107
+ def selected_returning
108
+ @selected_returning ||= returning.join(', ')
109
+ end
110
+
111
+ def upsert_returning
112
+ returning.map do |col|
113
+ qualify_column(col)
114
+ end.join(', ')
115
+ end
116
+
117
+ def qualify_column(col)
118
+ if (parts = coalesce_parts(col))
119
+ "coalesce(#{parts.map { |p| "#{p}.#{col}" }.join(', ')}) as #{col}"
94
120
  else
95
- updated_clause_template = <<~SQL
96
- ,updated as (
97
- %<updated_inner>s
98
- )
99
- SQL
100
- format(updated_clause_template, updated_inner:)
121
+ "selected.#{col}"
101
122
  end
102
123
  end
103
124
 
104
- def updated_inner
105
- @updated_inner ||= build_updated_inner
125
+ def coalesce_parts(col)
126
+ if col == primary_key || now_on_insert_only?(col)
127
+ %i[selected inserted]
128
+ elsif now_on_insert.include?(col) && now_on_update.include?(col)
129
+ %i[inserted updated selected]
130
+ end
106
131
  end
107
132
 
108
- def build_updated_inner
109
- format(UPDATED_INNER_TEMPLATE, table_name:, update_columns_text:)
133
+ def now_on_insert_only?(col)
134
+ now_on_insert.include?(col) && !now_on_update.include?(col)
110
135
  end
111
136
 
112
- def input_columns_text
113
- @input_columns_text ||= columns.map { |c| "input.#{c}" }.join(', ')
137
+ def join_sql
138
+ @join_sql ||= build_join_sql
114
139
  end
115
140
 
116
- def typed_columns_text
117
- @typed_columns_text ||= column_types.map { |pair| pair.join(' ') }.join(', ')
141
+ def build_join_sql
142
+ join_parts.map { |name| "left join #{name} #{using_sql}" }.join(' ')
143
+ end
144
+
145
+ def join_parts
146
+ if update_columns.empty?
147
+ [:inserted]
148
+ else
149
+ %i[inserted updated]
150
+ end
118
151
  end
119
152
 
120
- def columns_text
121
- @columns_text ||= columns.join(', ')
153
+ def using_sql
154
+ "using (#{query_columns_text})"
122
155
  end
123
156
 
124
157
  def query_columns_text
@@ -126,11 +159,17 @@ module BetterBatch
126
159
  end
127
160
 
128
161
  def update_columns
129
- @update_columns ||= columns - unique_columns
162
+ @update_columns ||= input_columns - unique_columns
130
163
  end
131
164
 
132
- def update_columns_text
133
- @update_columns_text ||= update_columns.map { |c| "#{c} = selected.#{c}" }.join(', ')
165
+ # modified from
166
+ # https://github.com/sonota88/anbt-sql-formatter/blob/main/bin/anbt-sql-formatter
167
+ def format_sql(src)
168
+ rule = AnbtSql::Rule.new
169
+ rule.keyword = AnbtSql::Rule::KEYWORD_LOWER_CASE
170
+ rule.indent_string = ' '
171
+ formatter = AnbtSql::Formatter.new(rule)
172
+ formatter.format(src)
134
173
  end
135
174
  end
136
175
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module BetterBatch
6
+ class Selected
7
+ extend Forwardable
8
+ def_delegators :@inputs, :table_name, :input_columns, :column_types, :unique_columns, :primary_key, :returning
9
+
10
+ ORDINAL = :better_batch_ordinal
11
+
12
+ TEMPLATE = <<~SQL
13
+ select %<selected_returning>s
14
+ from rows from (
15
+ jsonb_to_recordset($1)
16
+ as (%<typed_columns_sql>s)
17
+ ) with ordinality as input(%<input_columns_sql>s, %<ordinal>s)
18
+ left join %<table_name>s
19
+ using(%<query_columns_sql>s)
20
+ SQL
21
+
22
+ def initialize(inputs)
23
+ @inputs = inputs
24
+ end
25
+
26
+ def sql
27
+ params = { table_name:, primary_key:, selected_returning:, typed_columns_sql:, input_columns_sql:,
28
+ ordinal: ORDINAL, query_columns_sql: }
29
+ format(TEMPLATE, **params)
30
+ end
31
+
32
+ private
33
+
34
+ def selected_returning
35
+ @selected_returning ||= qualified_columns.join(', ')
36
+ end
37
+
38
+ def remaining_columns
39
+ @remaining_columns ||= returning - input_columns
40
+ end
41
+
42
+ def typed_columns_sql
43
+ @typed_columns_sql ||= input_columns.map { |c| "#{c} #{column_types[c]}" }.join(', ')
44
+ end
45
+
46
+ def input_columns_sql
47
+ @input_columns_sql ||= input_columns.join(', ')
48
+ end
49
+
50
+ def query_columns_sql
51
+ @query_columns_sql ||= unique_columns.join(', ')
52
+ end
53
+
54
+ def prefix_table(parts)
55
+ parts.map { |part| "#{table_name}.#{part}" }
56
+ end
57
+
58
+ def prefix_input(parts)
59
+ parts.map { |part| "input.#{part}" }
60
+ end
61
+
62
+ def columns
63
+ @columns ||= {
64
+ primary_key: [primary_key],
65
+ input_columns: input_columns - [primary_key],
66
+ remaining_columns: returning - [primary_key] - input_columns,
67
+ ordinal: ORDINAL
68
+ }
69
+ end
70
+
71
+ def qualified_columns
72
+ @qualified_columns ||= \
73
+ prefix_table(columns.fetch(:primary_key)) +
74
+ prefix_table(columns.fetch(:remaining_columns)) +
75
+ prefix_input(columns.fetch(:input_columns)) +
76
+ [columns.fetch(:ordinal)]
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module BetterBatch
6
+ class Updated
7
+ extend Forwardable
8
+ def_delegators :@inputs, :table_name, :input_columns, :column_types, :unique_columns, :primary_key, :now_on_update,
9
+ :returning
10
+
11
+ TEMPLATE = <<~SQL
12
+ update %<table_name>s
13
+ set %<set_sql>s
14
+ from selected where %<table_name>s.%<primary_key>s = selected.%<primary_key>s
15
+ returning %<returning_sql>s
16
+ SQL
17
+
18
+ def initialize(inputs)
19
+ @inputs = inputs
20
+ end
21
+
22
+ def sql
23
+ format(TEMPLATE, table_name:, primary_key:, set_sql:, returning_sql:)
24
+ end
25
+
26
+ private
27
+
28
+ def set_sql
29
+ (update_columns_sql + now_as_sql).join(', ')
30
+ end
31
+
32
+ def update_columns_sql
33
+ @update_columns_sql ||= update_columns.map { |c| "#{c} = selected.#{c}" }
34
+ end
35
+
36
+ def update_columns
37
+ @update_columns ||= input_columns - unique_columns
38
+ end
39
+
40
+ def now_as_sql
41
+ @now_as_sql ||= now_on_update.map { |c| "#{c} = now()" }
42
+ end
43
+
44
+ def returning_sql
45
+ @returning_sql ||= returning_cols.map { |c| "#{table_name}.#{c}" }.join(', ')
46
+ end
47
+
48
+ def returning_cols
49
+ (returning - input_columns - now_on_update) + unique_columns + now_on_update
50
+ end
51
+ end
52
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BetterBatch
4
- VERSION = '0.1.0'
4
+ VERSION = '1.0.2'
5
5
  end
metadata CHANGED
@@ -1,14 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_batch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Hartland
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-12 00:00:00.000000000 Z
11
- dependencies: []
10
+ date: 2025-04-15 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: anbt-sql-formatter
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.1'
12
26
  email:
13
27
  - tylerhartland7@gmail.com
14
28
  executables: []
@@ -17,13 +31,19 @@ extra_rdoc_files: []
17
31
  files:
18
32
  - ".rspec"
19
33
  - ".rubocop.yml"
34
+ - ".ruby-version"
20
35
  - CHANGELOG.md
21
36
  - CODE_OF_CONDUCT.md
22
37
  - LICENSE.txt
23
38
  - README.md
24
39
  - Rakefile
25
40
  - lib/better_batch.rb
41
+ - lib/better_batch/.DS_Store
42
+ - lib/better_batch/inputs.rb
43
+ - lib/better_batch/inserted.rb
26
44
  - lib/better_batch/query.rb
45
+ - lib/better_batch/selected.rb
46
+ - lib/better_batch/updated.rb
27
47
  - lib/better_batch/version.rb
28
48
  - sig/better_batch.rbs
29
49
  homepage: https://github.com/th7/better_batch
@@ -41,7 +61,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
41
61
  requirements:
42
62
  - - ">="
43
63
  - !ruby/object:Gem::Version
44
- version: 3.1.0
64
+ version: 3.2.0
45
65
  required_rubygems_version: !ruby/object:Gem::Requirement
46
66
  requirements:
47
67
  - - ">="