mini_sql 1.5.0 → 1.6.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 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