mini_sql 0.2.5 → 0.3
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/CHANGELOG +4 -0
- data/README.md +30 -1
- data/lib/mini_sql/connection.rb +14 -2
- data/lib/mini_sql/postgres/connection.rb +67 -1
- data/lib/mini_sql/postgres/deserializer_cache.rb +23 -0
- data/lib/mini_sql/version.rb +1 -1
- data/mini_sql.gemspec +1 -1
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ea4564f53848c314c76c45db0c2af652c1e128ebfc1ba52d6ae11b3799149f4
|
4
|
+
data.tar.gz: ecdfdc07fdf11e60338bc2ceb0415cbcc027720c5bba645281217a51befc2402
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76a040187f4932dc9fbc80ae3323633a38462753caec47233dbfad3e276e90d8eeb0fbddcbfe974ade3b0b99c18a487d5ef865ebdb1effc67048352ecd35d99d
|
7
|
+
data.tar.gz: 73c3519bf51a7934af89827830e3e7c45366eec01b1d65dc0c61afb2b87c12b093e9f3db99b1c4db081e6a6a1e983fd24d88db3aa13f63b9e546af0dce36beae
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -130,10 +130,12 @@ When using Postgres, native type mapping implementation is used. This is roughly
|
|
130
130
|
implemented as:
|
131
131
|
|
132
132
|
```ruby
|
133
|
-
type_map
|
133
|
+
type_map ||= PG::BasicTypeMapForResults.new(conn)
|
134
134
|
# additional specific decoders
|
135
135
|
```
|
136
136
|
|
137
|
+
The type mapper instansitated once on-demand at boot and reused by all mini_sql connections.
|
138
|
+
|
137
139
|
Initializing the basic type map for Postgres can be a costly operation. You may
|
138
140
|
wish to amend the type mapper so for example you only return strings:
|
139
141
|
|
@@ -158,6 +160,33 @@ mini_sql_cnn = MiniSql::Connection.get(pg_cnn, type_map: pg_cnn.type_map_for_res
|
|
158
160
|
|
159
161
|
Note the type mapper for Rails may miss some of the mapping MiniSql ships with such as `IPAddr`, MiniSql is also careful to use the very efficient TimestampUtc decoders where available.
|
160
162
|
|
163
|
+
## Streaming support
|
164
|
+
|
165
|
+
In some exceptional cases you may want to stream results directly from the database. This enables selection of 100s of thousands of rows with limited memory impact.
|
166
|
+
|
167
|
+
Two interfaces exists for this:
|
168
|
+
|
169
|
+
`query_each` : which can be used to get materialized objects
|
170
|
+
`query_each_hash` : which can be used to iterate through Hash objects
|
171
|
+
|
172
|
+
Usage:
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
mini_sql_cnn.query_each("SELECT * FROM tons_of_cows limit :limit", limit: 1_000_000) do |row|
|
176
|
+
puts row.cow_name
|
177
|
+
puts row.cow_age
|
178
|
+
end
|
179
|
+
|
180
|
+
mini_sql_cnn.query_each_hash("SELECT * FROM one_million_cows") do |row|
|
181
|
+
puts row["cow_name"]
|
182
|
+
puts row["cow_age"]
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
Note, in Postgres streaming is going to be slower than non-streaming options due to internal implementation in the pq gem, each row gets a full result object and additional bookkeeping is needed. Only use it if you need to optimize memory usage.
|
187
|
+
|
188
|
+
Streaming support is only implemented in the postgres backend at the moment, PRs welcome to add to other backends.
|
189
|
+
|
161
190
|
## I want more features!
|
162
191
|
|
163
192
|
MiniSql is designed to be very minimal. Even though the query builder and type materializer give you a lot of mileage, it is not intended to be a fully fledged ORM. If you are looking for an ORM I recommend investigating ActiveRecord or Sequel which provide significantly more features.
|
data/lib/mini_sql/connection.rb
CHANGED
@@ -31,11 +31,23 @@ module MiniSql
|
|
31
31
|
raise NotImplementedError, "must be implemented by child connection"
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
34
|
+
def query_hash(sql, *params)
|
35
35
|
raise NotImplementedError, "must be implemented by child connection"
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
38
|
+
def query_decorator(sql, *params)
|
39
|
+
raise NotImplementedError, "must be implemented by child connection"
|
40
|
+
end
|
41
|
+
|
42
|
+
def query_each(sql, *params)
|
43
|
+
raise NotImplementedError, "must be implemented by child connection"
|
44
|
+
end
|
45
|
+
|
46
|
+
def query_each_hash(sql, *params)
|
47
|
+
raise NotImplementedError, "must be implemented by child connection"
|
48
|
+
end
|
49
|
+
|
50
|
+
def exec(sql, *params)
|
39
51
|
raise NotImplementedError, "must be implemented by child connection"
|
40
52
|
end
|
41
53
|
|
@@ -83,7 +83,7 @@ module MiniSql
|
|
83
83
|
result = run(sql, params)
|
84
84
|
result.type_map = type_map
|
85
85
|
result.values
|
86
|
-
|
86
|
+
ensure
|
87
87
|
result.clear if result
|
88
88
|
end
|
89
89
|
|
@@ -95,6 +95,72 @@ module MiniSql
|
|
95
95
|
result.clear if result
|
96
96
|
end
|
97
97
|
|
98
|
+
def query_each(sql, *params)
|
99
|
+
raise StandardError, "Please supply a block when calling query_each" if !block_given?
|
100
|
+
if params && params.length > 0
|
101
|
+
sql = param_encoder.encode(sql, *params)
|
102
|
+
end
|
103
|
+
|
104
|
+
raw_connection.send_query(sql)
|
105
|
+
raw_connection.set_single_row_mode
|
106
|
+
|
107
|
+
loop do
|
108
|
+
result = raw_connection.get_result
|
109
|
+
break if !result
|
110
|
+
|
111
|
+
result.check
|
112
|
+
|
113
|
+
if result.ntuples == 0
|
114
|
+
# skip, this happens at the end when we get totals
|
115
|
+
else
|
116
|
+
materializer ||= @deserializer_cache.materializer(result)
|
117
|
+
result.type_map = type_map
|
118
|
+
i = 0
|
119
|
+
# technically we should only get 1 row here
|
120
|
+
# but protect against future batching changes
|
121
|
+
while i < result.ntuples
|
122
|
+
yield materializer.materialize(result, i)
|
123
|
+
i += 1
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
result.clear
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def query_each_hash(sql, *params)
|
132
|
+
raise StandardError, "Please supply a block when calling query_each_hash" if !block_given?
|
133
|
+
if params && params.length > 0
|
134
|
+
sql = param_encoder.encode(sql, *params)
|
135
|
+
end
|
136
|
+
|
137
|
+
raw_connection.send_query(sql)
|
138
|
+
raw_connection.set_single_row_mode
|
139
|
+
|
140
|
+
loop do
|
141
|
+
result = raw_connection.get_result
|
142
|
+
break if !result
|
143
|
+
|
144
|
+
result.check
|
145
|
+
|
146
|
+
if result.ntuples == 0
|
147
|
+
# skip, this happens at the end when we get totals
|
148
|
+
else
|
149
|
+
result.type_map = type_map
|
150
|
+
i = 0
|
151
|
+
|
152
|
+
# technically we should only get 1 row here
|
153
|
+
# but protect against future batching changes
|
154
|
+
while i < result.ntuples
|
155
|
+
yield result[i]
|
156
|
+
i += 1
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
result.clear
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
98
164
|
def query_decorator(decorator, sql, *params)
|
99
165
|
result = run(sql, params)
|
100
166
|
result.type_map = type_map
|
@@ -11,6 +11,20 @@ module MiniSql
|
|
11
11
|
@max_size = max_size || DEFAULT_MAX_SIZE
|
12
12
|
end
|
13
13
|
|
14
|
+
def materializer(result)
|
15
|
+
key = result.fields
|
16
|
+
|
17
|
+
materializer = @cache.delete(key)
|
18
|
+
if materializer
|
19
|
+
@cache[key] = materializer
|
20
|
+
else
|
21
|
+
materializer = @cache[key] = new_row_matrializer(result)
|
22
|
+
@cache.shift if @cache.length > @max_size
|
23
|
+
end
|
24
|
+
|
25
|
+
materializer
|
26
|
+
end
|
27
|
+
|
14
28
|
def materialize(result, decorator_module = nil)
|
15
29
|
return [] if result.ntuples == 0
|
16
30
|
|
@@ -42,6 +56,15 @@ module MiniSql
|
|
42
56
|
def new_row_matrializer(result)
|
43
57
|
fields = result.fields
|
44
58
|
|
59
|
+
i = 0
|
60
|
+
while i < fields.length
|
61
|
+
# special handling for unamed column
|
62
|
+
if fields[i] == "?column?"
|
63
|
+
fields[i] = "column#{i}"
|
64
|
+
end
|
65
|
+
i += 1
|
66
|
+
end
|
67
|
+
|
45
68
|
Class.new do
|
46
69
|
attr_accessor(*fields)
|
47
70
|
|
data/lib/mini_sql/version.rb
CHANGED
data/mini_sql.gemspec
CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.require_paths = ["lib"]
|
34
34
|
|
35
35
|
spec.add_development_dependency "bundler", "> 1.16"
|
36
|
-
spec.add_development_dependency "rake", "
|
36
|
+
spec.add_development_dependency "rake", "> 10"
|
37
37
|
spec.add_development_dependency "minitest", "~> 5.0"
|
38
38
|
spec.add_development_dependency "guard", "~> 2.14"
|
39
39
|
spec.add_development_dependency "guard-minitest", "~> 2.4"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_sql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '10
|
33
|
+
version: '10'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '10
|
40
|
+
version: '10'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: minitest
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -210,7 +210,7 @@ metadata:
|
|
210
210
|
bug_tracker_uri: https://github.com/discourse/mini_sql/issues
|
211
211
|
source_code_uri: https://github.com/discourse/mini_sql
|
212
212
|
changelog_uri: https://github.com/discourse/mini_sql/blob/master/CHANGELOG
|
213
|
-
post_install_message:
|
213
|
+
post_install_message:
|
214
214
|
rdoc_options: []
|
215
215
|
require_paths:
|
216
216
|
- lib
|
@@ -226,7 +226,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
226
226
|
version: '0'
|
227
227
|
requirements: []
|
228
228
|
rubygems_version: 3.0.3
|
229
|
-
signing_key:
|
229
|
+
signing_key:
|
230
230
|
specification_version: 4
|
231
231
|
summary: A fast, safe, simple direct SQL executor
|
232
232
|
test_files: []
|