simple_query 0.3.1 → 0.4.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 +4 -4
- data/README.md +65 -22
- data/lib/simple_query/builder.rb +48 -2
- data/lib/simple_query/clauses/join_clause.rb +23 -6
- data/lib/simple_query/clauses/set_clause.rb +25 -0
- data/lib/simple_query/stream/mysql_stream.rb +36 -0
- data/lib/simple_query/stream/postgres_stream.rb +59 -0
- data/lib/simple_query/version.rb +1 -1
- data/lib/simple_query.rb +10 -13
- metadata +7 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a62c7c2fe2d6c43a27b9cc2dd22e7ddcf14a01f9ca335144b472db1559f4b0a
|
4
|
+
data.tar.gz: 172eddfa79634dcf78d3547031af80a9f1e008dc9e0414c0f5671c66b4264617
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abbd8b5034e7b3a9a72b5de79f0d522a1ba2ac2b066bcc78387fb068ad9647b685c006318f6efafd31b5b616b48bd18ea677a5c74e7c25647a38c062a934109b
|
7
|
+
data.tar.gz: e499597efd33f703d136b0e053006ef109dea762e19148acd6bb5dcf6717f14f8b63845d61a3ea7b770353dd37e17178ca8b51ef7785e0714828ee78bda1fb8e
|
data/README.md
CHANGED
@@ -54,11 +54,12 @@ User.simple_query.select(:name, :email).where(active: true).execute
|
|
54
54
|
```
|
55
55
|
|
56
56
|
Query with join
|
57
|
+
|
58
|
+
SimpleQuery now supports **all major SQL join types** — including LEFT, RIGHT, and FULL — through the following DSL methods:
|
57
59
|
```ruby
|
58
60
|
User.simple_query
|
59
|
-
.
|
60
|
-
.
|
61
|
-
.where(Company.arel_table[:name].eq("TechCorp"))
|
61
|
+
.left_join(:users, :companies, foreign_key: :user_id, primary_key: :id)
|
62
|
+
.select("users.name", "companies.name")
|
62
63
|
.execute
|
63
64
|
```
|
64
65
|
|
@@ -143,9 +144,13 @@ class User < ActiveRecord::Base
|
|
143
144
|
where(admin: true)
|
144
145
|
end
|
145
146
|
|
147
|
+
# Block-based scope with parameter
|
146
148
|
simple_scope :by_name do |name|
|
147
149
|
where(name: name)
|
148
150
|
end
|
151
|
+
|
152
|
+
# Lambda-based scope with parameter
|
153
|
+
simple_scope :by_name, ->(name) { where(name: name) }
|
149
154
|
end
|
150
155
|
```
|
151
156
|
You can then chain these scopes seamlessly with the normal SimpleQuery DSL:
|
@@ -171,32 +176,70 @@ Each scope block (e.g. by_name) is evaluated in the context of the SimpleQuery b
|
|
171
176
|
Parameterized scopes accept arguments — passed directly to the block (e.g. |name| above).
|
172
177
|
Scopes return self, so you can chain multiple scopes or mix them with standard query methods.
|
173
178
|
|
174
|
-
##
|
179
|
+
## Streaming Large Datasets
|
180
|
+
|
181
|
+
For massive queries (millions of rows), **SimpleQuery** offers a `.stream_each` method to avoid loading the entire result set into memory. It **automatically** picks a streaming approach depending on your database adapter:
|
175
182
|
|
176
|
-
-
|
177
|
-
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
-
|
185
|
-
|
186
|
-
|
183
|
+
- **PostgreSQL**: Uses a **server-side cursor** via `DECLARE ... FETCH`.
|
184
|
+
- **MySQL**: Uses `mysql2` gem’s **streaming** (`stream: true, cache_rows: false, as: :hash`).
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
# Example usage:
|
188
|
+
User.simple_query
|
189
|
+
.where(active: true)
|
190
|
+
.stream_each(batch_size: 10_000) do |row|
|
191
|
+
# row is a struct or read-model instance
|
192
|
+
puts row.name
|
193
|
+
end
|
194
|
+
```
|
187
195
|
|
188
196
|
## Performance
|
189
197
|
|
190
|
-
SimpleQuery
|
198
|
+
SimpleQuery aims to outperform standard ActiveRecord queries at scale. We’ve benchmarked **1,000,000** records on **both PostgreSQL** and **MySQL**, with the following results:
|
199
|
+
|
200
|
+
### PostgreSQL (1,000,000 records)
|
201
|
+
```
|
202
|
+
🚀 Performance Results (1000,000 records):
|
203
|
+
ActiveRecord Query: 10.36932 seconds
|
204
|
+
SimpleQuery Execution (Struct): 3.46136 seconds
|
205
|
+
SimpleQuery Execution (Read model): 2.20905 seconds
|
206
|
+
|
207
|
+
----------------------------------------------------
|
208
|
+
ActiveRecord find_each: 6.10077 seconds
|
209
|
+
SimpleQuery stream_each: 2.75639 seconds
|
210
|
+
|
211
|
+
--- AR find_each Memory Report ---
|
212
|
+
Total allocated: 1.98 GB (16,001,659 objects)
|
213
|
+
Retained: ~2 KB
|
214
|
+
|
215
|
+
--- SimpleQuery stream_each Memory Report ---
|
216
|
+
Total allocated: 1.38 GB (8,000,211 objects)
|
217
|
+
Retained: ~3 KB
|
218
|
+
```
|
219
|
+
- **Struct-based** approach remains the fastest, skipping model overhead.
|
220
|
+
- **Read model** approach is still significantly faster than standard ActiveRecord while allowing domain-specific logic.
|
191
221
|
|
222
|
+
### MySQL (1,000,000 records)
|
192
223
|
```
|
193
|
-
🚀 Performance Results (
|
194
|
-
ActiveRecord Query:
|
195
|
-
SimpleQuery Execution (Struct):
|
196
|
-
SimpleQuery Execution (Read model):
|
224
|
+
🚀 Performance Results (1000,000 records):
|
225
|
+
ActiveRecord Query: 10.45833 seconds
|
226
|
+
SimpleQuery Execution (Struct): 3.04655 seconds
|
227
|
+
SimpleQuery Execution (Read model): 3.69052 seconds
|
228
|
+
|
229
|
+
----------------------------------------------------
|
230
|
+
ActiveRecord find_each: 5.04671 seconds
|
231
|
+
SimpleQuery stream_each: 2.96602 seconds
|
232
|
+
|
233
|
+
--- AR find_each Memory Report ---
|
234
|
+
Total allocated: 1.32 GB (11,001,445 objects)
|
235
|
+
Retained: ~2.7 KB
|
236
|
+
|
237
|
+
--- SimpleQuery stream_each Memory Report ---
|
238
|
+
Total allocated: 1.22 GB (8,000,068 objects)
|
239
|
+
Retained: ~3.9 KB
|
197
240
|
```
|
198
|
-
-
|
199
|
-
-
|
241
|
+
- Even in MySQL, **Struct** was roughly **three times faster** than ActiveRecord’s overhead.
|
242
|
+
- Read models still outperform AR, though by a narrower margin in this scenario.
|
200
243
|
|
201
244
|
## Development
|
202
245
|
|
data/lib/simple_query/builder.rb
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
module SimpleQuery
|
4
4
|
class Builder
|
5
|
+
include SimpleQuery::Stream::PostgresStream
|
6
|
+
include SimpleQuery::Stream::MysqlStream
|
7
|
+
|
5
8
|
attr_reader :model, :arel_table
|
6
9
|
|
7
10
|
def initialize(source)
|
@@ -34,12 +37,24 @@ module SimpleQuery
|
|
34
37
|
self
|
35
38
|
end
|
36
39
|
|
37
|
-
def join(table1, table2, foreign_key:, primary_key:)
|
38
|
-
@joins.add(table1, table2, foreign_key: foreign_key, primary_key: primary_key)
|
40
|
+
def join(table1, table2, foreign_key:, primary_key:, type: :inner)
|
41
|
+
@joins.add(table1, table2, foreign_key: foreign_key, primary_key: primary_key, join_type: type)
|
39
42
|
reset_query
|
40
43
|
self
|
41
44
|
end
|
42
45
|
|
46
|
+
def left_join(table1, table2, foreign_key:, primary_key:)
|
47
|
+
join(table1, table2, foreign_key: foreign_key, primary_key: primary_key, type: :left)
|
48
|
+
end
|
49
|
+
|
50
|
+
def right_join(table1, table2, foreign_key:, primary_key:)
|
51
|
+
join(table1, table2, foreign_key: foreign_key, primary_key: primary_key, type: :right)
|
52
|
+
end
|
53
|
+
|
54
|
+
def full_join(table1, table2, foreign_key:, primary_key:)
|
55
|
+
join(table1, table2, foreign_key: foreign_key, primary_key: primary_key, type: :full)
|
56
|
+
end
|
57
|
+
|
43
58
|
def order(order_conditions)
|
44
59
|
@orders.add(order_conditions)
|
45
60
|
reset_query
|
@@ -82,6 +97,30 @@ module SimpleQuery
|
|
82
97
|
self
|
83
98
|
end
|
84
99
|
|
100
|
+
def bulk_update(set:)
|
101
|
+
table_name = @arel_table.name
|
102
|
+
set_sql = SetClause.new(set).to_sql
|
103
|
+
|
104
|
+
raise ArgumentError, "No columns to update" if set_sql.empty?
|
105
|
+
|
106
|
+
where_sql = build_where_sql
|
107
|
+
sql = "UPDATE #{table_name} SET #{set_sql}"
|
108
|
+
sql += " WHERE #{where_sql}" unless where_sql.nil? || where_sql.empty?
|
109
|
+
|
110
|
+
ActiveRecord::Base.connection.execute(sql)
|
111
|
+
end
|
112
|
+
|
113
|
+
def stream_each(batch_size: 1000, &block)
|
114
|
+
adapter = ActiveRecord::Base.connection.adapter_name.downcase
|
115
|
+
if adapter.include?("postgres")
|
116
|
+
stream_each_postgres(batch_size, &block)
|
117
|
+
elsif adapter.include?("mysql")
|
118
|
+
stream_each_mysql(&block)
|
119
|
+
else
|
120
|
+
raise "stream_each is only implemented for Postgres and MySQL."
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
85
124
|
def execute
|
86
125
|
records = ActiveRecord::Base.connection.select_all(cached_sql)
|
87
126
|
build_result_objects_from_rows(records)
|
@@ -121,6 +160,13 @@ module SimpleQuery
|
|
121
160
|
|
122
161
|
private
|
123
162
|
|
163
|
+
def build_where_sql
|
164
|
+
condition = @wheres.to_arel
|
165
|
+
return "" unless condition
|
166
|
+
|
167
|
+
condition.to_sql
|
168
|
+
end
|
169
|
+
|
124
170
|
def reset_query
|
125
171
|
@query_built = false
|
126
172
|
@query_cache.clear
|
@@ -8,20 +8,37 @@ module SimpleQuery
|
|
8
8
|
@joins = []
|
9
9
|
end
|
10
10
|
|
11
|
-
def add(table1, table2, foreign_key:, primary_key:)
|
11
|
+
def add(table1, table2, foreign_key:, primary_key:, join_type: :inner)
|
12
12
|
@joins << {
|
13
13
|
table1: to_arel_table(table1),
|
14
14
|
table2: to_arel_table(table2),
|
15
15
|
foreign_key: foreign_key,
|
16
|
-
primary_key: primary_key
|
16
|
+
primary_key: primary_key,
|
17
|
+
type: join_type
|
17
18
|
}
|
18
19
|
end
|
19
20
|
|
20
21
|
def apply_to(query)
|
21
|
-
@joins.each do |
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
@joins.each do |join_def|
|
23
|
+
table1 = join_def[:table1]
|
24
|
+
table2 = join_def[:table2]
|
25
|
+
fk = join_def[:foreign_key]
|
26
|
+
pk = join_def[:primary_key]
|
27
|
+
type = join_def[:type]
|
28
|
+
|
29
|
+
join_class = case type
|
30
|
+
when :left
|
31
|
+
Arel::Nodes::OuterJoin
|
32
|
+
when :right
|
33
|
+
Arel::Nodes::RightOuterJoin
|
34
|
+
when :full
|
35
|
+
Arel::Nodes::FullOuterJoin
|
36
|
+
else
|
37
|
+
Arel::Nodes::InnerJoin
|
38
|
+
end
|
39
|
+
|
40
|
+
condition = table2[fk].eq(table1[pk])
|
41
|
+
query.join(table2, join_class).on(condition)
|
25
42
|
end
|
26
43
|
query
|
27
44
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SimpleQuery
|
4
|
+
class SetClause
|
5
|
+
def initialize(set_hash)
|
6
|
+
@set_hash = set_hash
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_sql
|
10
|
+
@set_hash.map do |col, val|
|
11
|
+
"#{quote_column(col)} = #{quote_value(val)}"
|
12
|
+
end.join(", ")
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def quote_column(col)
|
18
|
+
ActiveRecord::Base.connection.quote_column_name(col)
|
19
|
+
end
|
20
|
+
|
21
|
+
def quote_value(val)
|
22
|
+
ActiveRecord::Base.connection.quote(val)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SimpleQuery
|
4
|
+
module Stream
|
5
|
+
module MysqlStream
|
6
|
+
def stream_each_mysql(&block)
|
7
|
+
select_sql = cached_sql
|
8
|
+
|
9
|
+
raw_conn = ActiveRecord::Base.connection.raw_connection
|
10
|
+
|
11
|
+
result = raw_conn.query(select_sql, stream: true, cache_rows: false, as: :hash)
|
12
|
+
result.each do |mysql_row|
|
13
|
+
record = build_row_object_mysql(mysql_row)
|
14
|
+
block.call(record)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build_row_object_mysql(mysql_row)
|
21
|
+
if @read_model_class
|
22
|
+
obj = @read_model_class.allocate
|
23
|
+
@read_model_class.attributes.each do |attr_name, col_name|
|
24
|
+
obj.instance_variable_set(:"@#{attr_name}", mysql_row[col_name])
|
25
|
+
end
|
26
|
+
obj
|
27
|
+
else
|
28
|
+
columns = mysql_row.keys
|
29
|
+
values = columns.map { |k| mysql_row[k] }
|
30
|
+
struct = result_struct(columns)
|
31
|
+
struct.new(*values)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SimpleQuery
|
4
|
+
module Stream
|
5
|
+
module PostgresStream
|
6
|
+
# rubocop:disable Metrics/MethodLength
|
7
|
+
def stream_each_postgres(batch_size, &block)
|
8
|
+
select_sql = cached_sql
|
9
|
+
|
10
|
+
conn = ActiveRecord::Base.connection.raw_connection
|
11
|
+
cursor_name = "simple_query_cursor_#{object_id}"
|
12
|
+
|
13
|
+
begin
|
14
|
+
conn.exec("BEGIN")
|
15
|
+
declare_sql = "DECLARE #{cursor_name} NO SCROLL CURSOR FOR #{select_sql}"
|
16
|
+
conn.exec(declare_sql)
|
17
|
+
|
18
|
+
loop do
|
19
|
+
res = conn.exec("FETCH #{batch_size} FROM #{cursor_name}")
|
20
|
+
break if res.ntuples.zero?
|
21
|
+
|
22
|
+
res.each do |pg_row|
|
23
|
+
record = build_row_object(pg_row)
|
24
|
+
block.call(record)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
conn.exec("CLOSE #{cursor_name}")
|
29
|
+
conn.exec("COMMIT")
|
30
|
+
rescue StandardError => e
|
31
|
+
begin
|
32
|
+
conn.exec("ROLLBACK")
|
33
|
+
rescue StandardError
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
raise e
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# rubocop:enable Metrics/MethodLength
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def build_row_object(pg_row)
|
44
|
+
if @read_model_class
|
45
|
+
obj = @read_model_class.allocate
|
46
|
+
@read_model_class.attributes.each do |attr_name, col_name|
|
47
|
+
obj.instance_variable_set(:"@#{attr_name}", pg_row[col_name])
|
48
|
+
end
|
49
|
+
obj
|
50
|
+
else
|
51
|
+
columns = pg_row.keys
|
52
|
+
values = columns.map { |k| pg_row[k] }
|
53
|
+
struct = result_struct(columns)
|
54
|
+
struct.new(*values)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/simple_query/version.rb
CHANGED
data/lib/simple_query.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require "active_support/concern"
|
4
4
|
require "active_record"
|
5
5
|
|
6
|
+
require_relative "simple_query/stream/mysql_stream"
|
7
|
+
require_relative "simple_query/stream/postgres_stream"
|
6
8
|
require_relative "simple_query/builder"
|
7
9
|
require_relative "simple_query/read_model"
|
8
10
|
require_relative "simple_query/clauses/where_clause"
|
@@ -11,6 +13,7 @@ require_relative "simple_query/clauses/order_clause"
|
|
11
13
|
require_relative "simple_query/clauses/distinct_clause"
|
12
14
|
require_relative "simple_query/clauses/limit_offset_clause"
|
13
15
|
require_relative "simple_query/clauses/group_having_clause"
|
16
|
+
require_relative "simple_query/clauses/set_clause"
|
14
17
|
|
15
18
|
module SimpleQuery
|
16
19
|
extend ActiveSupport::Concern
|
@@ -41,19 +44,13 @@ module SimpleQuery
|
|
41
44
|
@_simple_scopes ||= {}
|
42
45
|
end
|
43
46
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
# simple_scope :by_name do |name|
|
52
|
-
# where(name: name)
|
53
|
-
# end
|
54
|
-
#
|
55
|
-
def simple_scope(name, &block)
|
56
|
-
_simple_scopes[name.to_sym] = block
|
47
|
+
def simple_scope(name, body = nil, &block)
|
48
|
+
raise ArgumentError, "Pass either a proc/lambda or a block, not both" if body && block_given?
|
49
|
+
|
50
|
+
scope_body = body || block
|
51
|
+
raise ArgumentError, "You must provide a block or a proc" unless scope_body
|
52
|
+
|
53
|
+
_simple_scopes[name.to_sym] = scope_body
|
57
54
|
end
|
58
55
|
end
|
59
56
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_query
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Kholodniak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -30,62 +30,6 @@ dependencies:
|
|
30
30
|
- - "<="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '8.0'
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: rake
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '13.0'
|
40
|
-
type: :development
|
41
|
-
prerelease: false
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '13.0'
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: rspec
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '3.0'
|
54
|
-
type: :development
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - "~>"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '3.0'
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: rubocop
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - "~>"
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '1.21'
|
68
|
-
type: :development
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - "~>"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '1.21'
|
75
|
-
- !ruby/object:Gem::Dependency
|
76
|
-
name: sqlite3
|
77
|
-
requirement: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
79
|
-
- - "~>"
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: 1.5.0
|
82
|
-
type: :development
|
83
|
-
prerelease: false
|
84
|
-
version_requirements: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - "~>"
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: 1.5.0
|
89
33
|
description: SimpleQuery provides a flexible and performant way to construct complex
|
90
34
|
database queries in Ruby on Rails applications. It offers an intuitive interface
|
91
35
|
for building queries with joins, conditions, and aggregations, while potentially
|
@@ -105,8 +49,11 @@ files:
|
|
105
49
|
- lib/simple_query/clauses/join_clause.rb
|
106
50
|
- lib/simple_query/clauses/limit_offset_clause.rb
|
107
51
|
- lib/simple_query/clauses/order_clause.rb
|
52
|
+
- lib/simple_query/clauses/set_clause.rb
|
108
53
|
- lib/simple_query/clauses/where_clause.rb
|
109
54
|
- lib/simple_query/read_model.rb
|
55
|
+
- lib/simple_query/stream/mysql_stream.rb
|
56
|
+
- lib/simple_query/stream/postgres_stream.rb
|
110
57
|
- lib/simple_query/version.rb
|
111
58
|
homepage: https://github.com/kholdrex/simple_query
|
112
59
|
licenses:
|
@@ -133,5 +80,6 @@ requirements: []
|
|
133
80
|
rubygems_version: 3.5.9
|
134
81
|
signing_key:
|
135
82
|
specification_version: 4
|
136
|
-
summary: A lightweight and
|
83
|
+
summary: A lightweight, multi-DB-friendly, and high-performance query builder for
|
84
|
+
ActiveRecord, featuring streaming, bulk updates, and read-model support.
|
137
85
|
test_files: []
|