better_batch-active_record 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fc3cedf70ce459807c93814252ed8c4db04ccba0288e829b40f92d49df1efe21
4
+ data.tar.gz: 8062fff1d56372dd65eb20a4bd016022c8c81fc50363648a286a0485c0ad67bd
5
+ SHA512:
6
+ metadata.gz: 793b02a682e20a0ac01cde09d59a91d642b24bf0453eef62d51924111335d0e7f307526274cf434b3b8467934106a91b85357b9c23794a9378e7009a0eb6dfc5
7
+ data.tar.gz: 542b42bc0e4b7891936d97f0513f5b10ab0ea889d8e5d68c5454a52c140cf89b33e10a8c405f45bb5f1edc5ad6ac419c832cfafff806c4e8f330ff493b63ae38
data/lib/.DS_Store ADDED
Binary file
Binary file
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'better_batch/active_record/query'
4
+
5
+ module BetterBatch
6
+ module ActiveRecord
7
+ module Model
8
+ def better_batch
9
+ Query.new(self)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'better_batch/query'
4
+
5
+ module BetterBatch
6
+ module ActiveRecord
7
+ class Query
8
+ def initialize(model)
9
+ @model = model
10
+ end
11
+
12
+ def upsert(data, unique_by:, returning:)
13
+ query = build_query(data, unique_by:, returning:)
14
+ result = exec_query(:upsert, query, data)
15
+ case returning
16
+ when Symbol
17
+ result.rows.map(&:first)
18
+ when nil
19
+ nil
20
+ else
21
+ hash_rows(query.returning, result.rows)
22
+ end
23
+ end
24
+
25
+ def with_upserted_pk(data, unique_by:)
26
+ query = build_query(data, unique_by:, returning: primary_key)
27
+ data.zip(exec_query(:upsert, query, data).rows.map(&:first))
28
+ end
29
+
30
+ def set_upserted_pk(data, unique_by:)
31
+ with_upserted_pk(data, unique_by:).each do |row, pk|
32
+ row[primary_key] = pk
33
+ end
34
+ nil
35
+ end
36
+
37
+ def select(data, unique_by:, returning:)
38
+ query = build_query(data, unique_by:, returning:)
39
+ result = exec_query(:select, query, data)
40
+ case returning
41
+ when Symbol
42
+ result.rows.map(&:first)
43
+ when nil
44
+ nil
45
+ else
46
+ hash_rows(query.returning, result.rows)
47
+ end
48
+ end
49
+
50
+ def with_selected_pk(data, unique_by:)
51
+ query = build_query(data, unique_by:, returning: primary_key)
52
+ data.zip(exec_query(:select, query, data).rows.map(&:first))
53
+ end
54
+
55
+ def set_selected_pk(data, unique_by:)
56
+ with_upserted_pk(data, unique_by:).each do |row, pk|
57
+ row[primary_key] = pk
58
+ end
59
+ nil
60
+ end
61
+
62
+ private
63
+
64
+ attr_reader :model
65
+
66
+ def build_query(data, unique_by:, returning:)
67
+ array_data = data.to_a
68
+ unique_columns = Array(unique_by)
69
+ input_columns = array_data.first.keys
70
+ returning = Array(returning)
71
+ BetterBatch::Query.new(table_name:, primary_key:, input_columns:, column_types:, unique_columns:,
72
+ now_on_insert:, now_on_update:, returning:)
73
+ end
74
+
75
+ def exec_query(type, query, data)
76
+ sql = build_sql(type, query)
77
+ json_data = JSON.generate(data)
78
+ db_exec(sql, query, json_data)
79
+ end
80
+
81
+ def build_sql(type, query)
82
+ query.public_send(type)
83
+ rescue StandardError
84
+ raise query.inspect
85
+ end
86
+
87
+ def db_exec(sql, query, json_data)
88
+ model.connection.exec_query(sql, nil, [json_data])
89
+ rescue StandardError
90
+ raise [query.inspect, query.upsert_formatted].join("\n")
91
+ end
92
+
93
+ def table_name
94
+ @table_name ||= model.table_name
95
+ end
96
+
97
+ def primary_key
98
+ model.primary_key.to_sym
99
+ end
100
+
101
+ def column_types
102
+ @column_types ||= model.columns.to_h { |c| [c.name.to_sym, c.sql_type] }
103
+ end
104
+
105
+ def now_on_insert
106
+ [created_at_if_present, updated_at_if_present].compact
107
+ end
108
+
109
+ def now_on_update
110
+ updated_at_if_present
111
+ end
112
+
113
+ def created_at_if_present
114
+ :created_at if column_types.key?(:created_at)
115
+ end
116
+
117
+ def updated_at_if_present
118
+ :updated_at if column_types.key?(:updated_at)
119
+ end
120
+
121
+ def hash_rows(returning, rows)
122
+ # avoid building an entire new hash (which would rehash keys) for each row
123
+ # we only need to sub in the values
124
+ indexes = returning.each_with_index.to_h.freeze
125
+ rows.map do |row|
126
+ indexes.transform_values { |index| row[index] }
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterBatch
4
+ module ActiveRecord
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterBatch
4
+ module ActiveRecord
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: better_batch-active_record
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Hartland
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2025-04-16 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activerecord
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '7'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9'
32
+ - !ruby/object:Gem::Dependency
33
+ name: better_batch
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '1'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '1'
46
+ email:
47
+ - tylerhartland7@gmail.com
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - lib/.DS_Store
53
+ - lib/better_batch/.DS_Store
54
+ - lib/better_batch/active_record.rb
55
+ - lib/better_batch/active_record/model.rb
56
+ - lib/better_batch/active_record/query.rb
57
+ - lib/better_batch/active_record/version.rb
58
+ homepage: https://github.com/th7/better_batch-active_record
59
+ licenses:
60
+ - MIT
61
+ metadata:
62
+ allowed_push_host: https://rubygems.org
63
+ source_code_uri: https://github.com/th7/better_batch-active_record
64
+ rubygems_mfa_required: 'true'
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 3.2.0
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.6.2
80
+ specification_version: 4
81
+ summary: Better batch operations.
82
+ test_files: []