mini_sql 1.5.0 → 1.6.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
2
  SHA256:
3
- metadata.gz: 491de0ce7925ad9ec428409af4a78e5ce3f91b6f886bfcca7c17544a4b44e23a
4
- data.tar.gz: 2269da4aa96ec6d58c2141b82cae6d3764664e312ada254fe7f45476e6cb5b55
3
+ metadata.gz: 1160fe3ddc5b4d248f62efcb205d6bc83982912355a932f23ab9620fbbd0c8fe
4
+ data.tar.gz: f60fe47f807aa8273ce5d018611f111b0e99b21552ac258ac0b8594035fb0725
5
5
  SHA512:
6
- metadata.gz: dddf4370cdff6041fc2a0ceb338aa387ddcca76b65e135838cd0c3a1bfcf0bd0fcae37ea7504052b89b505b8c5478fb6d11e260e2349e25131b01853d42eae2d
7
- data.tar.gz: 8d2f7087f39d05a4e8ccf72e675a07a38d9f371bdcfef33d96589a085f13abef53feb6986668fb12c75886ff9db301c0b7753b36e72177ef33944f08ce347734
6
+ metadata.gz: ca800672b020af15bb69ca8b3cad63d435835c67f27d052ee01039eb31b7f0f8c4719ca9330f3ada3ff29b4442f2f423861686876e004d72bad7116be9b08235
7
+ data.tar.gz: 9394f995fe546af9c908597928699f7a1214dc3b5ae18ddb4a224b2c1d335da4a17be63c6e4b25adc0b8984af43259eec1ebaec0ceeceef31678115dbe790cae
@@ -36,7 +36,7 @@ jobs:
36
36
  strategy:
37
37
  fail-fast: false
38
38
  matrix:
39
- ruby: ["3.1", "3.0", "2.7"]
39
+ ruby: ["3.1", "3.2", "3.3"]
40
40
  experimental: [false]
41
41
  include:
42
42
  - ruby: ruby-head
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ 2024-08-21 - 1.6.0
2
+
3
+ - FEATURE: optionaly allow encoding pg arrays efficiently
4
+ - FEATURE: decoder for pgvector
5
+
1
6
  2023-08-16 - 1.5.0
2
7
 
3
8
  - FEATURE: add to_sql for easy conversion of builder to sql
data/README.md CHANGED
@@ -56,6 +56,15 @@ p conn.query_array("select 1 as a, '2' as b union select 3, 'e'").to_h
56
56
  # {1 => '2', 3 => 'e'}
57
57
  ```
58
58
 
59
+ ## Auto Encode Arrays (only PostgreSQL)
60
+ ```ruby
61
+ pg_conn = PG.connect(db_name: 'my_db')
62
+ conn = MiniSql::Connection.get(pg_conn, auto_encode_arrays: true)
63
+
64
+ # select * from table where id = ANY('{1,2,3}')
65
+ conn.query("select * from table where id = ANY(?)", [1, 2, 3])
66
+ ```
67
+
59
68
  ## The query builder
60
69
 
61
70
  You can use the simple query builder interface to compose queries.
@@ -241,15 +250,33 @@ Streaming support is only implemented in the postgres backend at the moment, PRs
241
250
  See [benchmark mini_sql](https://github.com/discourse/mini_sql/tree/master/bench/prepared_perf.rb)
242
251
  [benchmark mini_sql vs rails](https://github.com/discourse/mini_sql/tree/master/bench/bilder_perf.rb).
243
252
 
244
- By default prepared cache size is 500 queries. Use prepared queries only for frequent queries.
245
-
246
253
  ```ruby
247
254
  conn.prepared.query("select * from table where id = ?", id: 10)
255
+ ```
256
+
257
+ ### Prepared Statement Bloat in PostgreSQL
258
+ By default prepared cache size is __500__ queries per connection. Use prepared queries only for frequent queries.
259
+
260
+ The following code will create 100 prepared statements in PostgreSQL for a single database connection:
248
261
 
249
- ids = rand(100) < 90 ? [1] : [1, 2]
250
- builder = conn.build("select * from table /*where*/")
251
- builder.where("id IN (?)", ids)
252
- builder.prepared(ids.size == 1).query # most frequent query
262
+ ```ruby
263
+ 100.times do |i|
264
+ ids = (1..i).to_a
265
+ conn.prepared.query("SELECT * FROM table WHERE id IN (?)", ids)
266
+ end
267
+ ```
268
+
269
+ This can lead to high memory usage and performance issues due to the overhead of maintaining numerous prepared statements.
270
+
271
+ To improve performance, you can enable `auto_encode_arrays: true`. With this option, only one prepared statement is created, regardless of the size of ids:
272
+
273
+ ```ruby
274
+ pg_conn = PG.connect(db_name: 'my_db')
275
+ conn = MiniSql::Connection.get(pg_conn, auto_encode_arrays: true)
276
+ 100.times do |i|
277
+ ids = (1..i).to_a
278
+ conn.prepared.query("select * from table where id = ANY (?)", ids)
279
+ end
253
280
  ```
254
281
 
255
282
  ## Active Record Postgres
@@ -276,7 +303,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
276
303
  export MINI_SQL_MYSQL_HOST=127.0.0.1
277
304
  export MINI_SQL_MYSQL_PORT=33306
278
305
 
279
- docker run --name mini-sql-postgres --rm -it -p 55432:5432 -e POSTGRES_DB=test_mini_sql -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres
306
+ docker run --name mini-sql-postgres --rm -it -p 55432:5432 -e POSTGRES_DB=test_mini_sql -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres # or ankane/pgvector for testing vector type decoder
280
307
  export MINI_SQL_PG_USER=postgres
281
308
  export MINI_SQL_PG_HOST=127.0.0.1
282
309
  export MINI_SQL_PG_PORT=55432
@@ -2,10 +2,11 @@
2
2
 
3
3
  module MiniSql
4
4
  class InlineParamEncoder
5
- attr_reader :conn
5
+ attr_reader :conn, :array_encoder
6
6
 
7
- def initialize(conn)
7
+ def initialize(conn, array_encoder = nil)
8
8
  @conn = conn
9
+ @array_encoder = array_encoder
9
10
  end
10
11
 
11
12
  def encode(sql, *params)
@@ -62,7 +63,7 @@ module MiniSql
62
63
  when false then "false"
63
64
  when nil then "NULL"
64
65
  when [] then "NULL"
65
- when Array then value.map { |v| quote_val(v) }.join(', ')
66
+ when Array then array_encoder ? "'#{array_encoder.encode(value)}'" : value.map { |v| quote_val(v) }.join(', ')
66
67
  else raise TypeError, "can't quote #{value.class.name}"
67
68
  end
68
69
  end
@@ -26,6 +26,20 @@ module MiniSql
26
26
  else
27
27
  map.add_coder(MiniSql::Postgres::Coders::TimestampUtc.new(name: "timestamp", oid: 1114, format: 0))
28
28
  end
29
+
30
+ if defined? Pgvector::PG
31
+ vector_oid =
32
+ PG::BasicTypeRegistry::CoderMapsBundle
33
+ .new(conn)
34
+ .typenames_by_oid
35
+ .find { |k, v| v == "vector" }
36
+ &.first
37
+
38
+ if !vector_oid.nil?
39
+ map.add_coder(Pgvector::PG::TextDecoder::Vector.new(name: "vector", oid: vector_oid, format: 0))
40
+ map.add_coder(Pgvector::PG::BinaryDecoder::Vector.new(name: "vector", oid: vector_oid, format: 1))
41
+ end
42
+ end
29
43
  map
30
44
  end
31
45
  end
@@ -38,7 +52,8 @@ module MiniSql
38
52
  def initialize(raw_connection, args = nil)
39
53
  @raw_connection = raw_connection
40
54
  @deserializer_cache = (args && args[:deserializer_cache]) || self.class.default_deserializer_cache
41
- @param_encoder = (args && args[:param_encoder]) || InlineParamEncoder.new(self)
55
+ array_encoder = PG::TextEncoder::Array.new if args && args[:auto_encode_arrays]
56
+ @param_encoder = (args && args[:param_encoder]) || InlineParamEncoder.new(self, array_encoder)
42
57
  @type_map = args && args[:type_map]
43
58
  end
44
59
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module MiniSql
3
- VERSION = "1.5.0"
3
+ VERSION = "1.6.0"
4
4
  end
data/mini_sql.gemspec CHANGED
@@ -49,5 +49,8 @@ Gem::Specification.new do |spec|
49
49
  spec.add_development_dependency "mysql2"
50
50
  spec.add_development_dependency "sqlite3", "~> 1.4.4"
51
51
  spec.add_development_dependency "activerecord", "~> 7.0.0"
52
+ if RUBY_VERSION >= "3.0"
53
+ spec.add_development_dependency "pgvector", "~> 0.2.1"
54
+ end
52
55
  end
53
56
  end
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: 1.5.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-16 00:00:00.000000000 Z
11
+ date: 2024-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler