simple-sql 0.5.27 → 0.5.32

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: fd927c6b8b525593892421de3ce43fefa20d036c3d3eaf3ee3f0bbb863108deb
4
- data.tar.gz: 2765ce9e6f3e86801074b014f142a607673f04692c6b0d8d3424c024066f25c9
3
+ metadata.gz: fb4af8eb0802b84e83370417d134ff18f82c812dbd9a053853739d9570f92a95
4
+ data.tar.gz: 0b023420320187d12f32cb6e1a4a093775a5bd2849015443768b0177392729fb
5
5
  SHA512:
6
- metadata.gz: b4737e323e981525a17129dfdfd1e5a8076e99350ae0f758d6e5d53386ecd57e8d1c66766dbf8ded98b6fdf14ca25ee5a2a616b6c3ae04b844917d71f2ad720a
7
- data.tar.gz: 8a86b32006f6bf1713c71550ea4a32bf4c393558ec8d76738d9905cae114bb470404c5168c10b352b5394b2ea7230277b931089cea9f15110e04522cb279cd5c
6
+ metadata.gz: 996461571d090b5cf7589dfc6f1d12925b11b54d047fc2ec2395bbb6a2d75e583a7f82d0cc92985982891d3254e3e26a83260f6a38be5bee0eac5872effb4609
7
+ data.tar.gz: 57decbf1a834422bdfc2987056c3fa37f04988de7059ed8c6eb8aa64ffc16c445a19f1dc9e91f880eac8a2ea7e8772dcfb8b1aeaf43b57ca7f13d4662ceaf177
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'byebug'
3
+ gem 'pry-byebug'
4
4
  gem 'rubocop', '~> 0.57.2'
5
5
 
6
6
  # Specify your gem's dependencies in {gemname}.gemspec
data/Makefile CHANGED
@@ -1,15 +1,15 @@
1
1
  tests: test4 test5 test6
2
2
 
3
3
  test4:
4
- SIMPLE_SQL_ACTIVERECORD_SPECS="< 5" bundle
4
+ SIMPLE_SQL_ACTIVERECORD_SPECS="> 4,< 5" bundle
5
5
  rspec
6
6
 
7
7
  test5:
8
- SIMPLE_SQL_ACTIVERECORD_SPECS="< 6" bundle
8
+ SIMPLE_SQL_ACTIVERECORD_SPECS="> 5,< 6" bundle update activerecord
9
9
  rspec
10
10
 
11
11
  test6:
12
- SIMPLE_SQL_ACTIVERECORD_SPECS="< 7" bundle
12
+ SIMPLE_SQL_ACTIVERECORD_SPECS="> 6,< 7" bundle update activerecord
13
13
  rspec
14
14
 
15
15
  stats:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.27
1
+ 0.5.32
data/config/database.yml CHANGED
@@ -2,7 +2,8 @@ defaults: &defaults
2
2
  adapter: postgresql
3
3
  encoding: utf8
4
4
  host: '127.0.0.1'
5
- # username: postgres
5
+ username: admin
6
+ password: admin
6
7
  pool: 5
7
8
  timeout: 5000
8
9
 
data/lib/simple/sql.rb CHANGED
@@ -12,6 +12,7 @@ require_relative "sql/config"
12
12
  require_relative "sql/logging"
13
13
  require_relative "sql/connection"
14
14
  require_relative "sql/table_print"
15
+ require_relative "sql/monkey_patches"
15
16
 
16
17
  module Simple
17
18
  # The Simple::SQL module
@@ -84,6 +84,7 @@ class Simple::SQL::Connection::Scope
84
84
  dupe.instance_variable_set :@page, @page
85
85
  dupe.instance_variable_set :@order_by_fragment, @order_by_fragment
86
86
  dupe.instance_variable_set :@limit, @limit
87
+ dupe.instance_variable_set :@offset, @offset
87
88
  dupe
88
89
  end
89
90
 
@@ -3,8 +3,16 @@ class Simple::SQL::Connection::Scope
3
3
  duplicate.send(:order_by!, sql_fragment)
4
4
  end
5
5
 
6
- def limit(count)
7
- duplicate.send(:limit!, count)
6
+ def limit(limit)
7
+ raise ArgumentError, "limit must be >= 0" unless limit >= 0
8
+
9
+ duplicate.send(:limit!, limit)
10
+ end
11
+
12
+ def offset(offset)
13
+ raise ArgumentError, "offset must be >= 0" unless offset >= 0
14
+
15
+ duplicate.send(:offset!, offset)
8
16
  end
9
17
 
10
18
  private
@@ -21,10 +29,16 @@ class Simple::SQL::Connection::Scope
21
29
  self
22
30
  end
23
31
 
32
+ def offset!(offset)
33
+ @offset = offset
34
+ self
35
+ end
36
+
24
37
  # called from to_sql
25
38
  def apply_order_and_limit(sql)
26
39
  sql = "#{sql} ORDER BY #{@order_by_fragment}" if @order_by_fragment
27
40
  sql = "#{sql} LIMIT #{@limit}" if @limit
41
+ sql = "#{sql} OFFSET #{@offset}" if @offset
28
42
 
29
43
  sql
30
44
  end
@@ -3,6 +3,9 @@
3
3
  class Simple::SQL::Connection::Scope
4
4
  # Set pagination
5
5
  def paginate(per:, page:)
6
+ raise ArgumentError, "per must be > 0" unless per > 0
7
+ raise ArgumentError, "page must be > 0" unless page > 0
8
+
6
9
  duplicate.send(:paginate!, per: per, page: page)
7
10
  end
8
11
 
@@ -23,8 +26,7 @@ class Simple::SQL::Connection::Scope
23
26
  def apply_pagination(sql, pagination:)
24
27
  return sql unless pagination == :auto && @per && @page
25
28
 
26
- raise ArgumentError, "per must be > 0" unless @per > 0
27
- raise ArgumentError, "page must be > 0" unless @page > 0
29
+ raise ArgumentError, "You cannot mix 'paginate' and 'offset'/'limit'" if @offset || @limit
28
30
 
29
31
  "#{sql} LIMIT #{@per} OFFSET #{(@page - 1) * @per}"
30
32
  end
@@ -8,11 +8,27 @@ module Simple::SQL::Helpers::Encoder
8
8
 
9
9
  def encode_arg(connection, arg)
10
10
  return arg unless arg.is_a?(Array)
11
+ return "{}" if arg.empty?
11
12
 
12
- if arg.first.is_a?(String)
13
- "{#{arg.map { |a| "\"#{connection.escape(a)}\"" }.join(',')}}"
13
+ encoded_ary = encode_array(connection, arg)
14
+ "{" + encoded_ary.join(",") + "}"
15
+ end
16
+
17
+ def encode_array(connection, ary)
18
+ case ary.first
19
+ when String
20
+ ary.map do |str|
21
+ str = connection.escape(str)
22
+
23
+ # These fixes have been discovered during tests. see spec/simple/sql/conversion_spec.rb
24
+ str = str.gsub("\"", "\\\"")
25
+ str = str.gsub("''", "'")
26
+ "\"#{str}\""
27
+ end
28
+ when Integer
29
+ ary
14
30
  else
15
- "{#{arg.join(',')}}"
31
+ raise ArgumentError, "Don't know how to encode array of #{ary.first.class}"
16
32
  end
17
33
  end
18
34
  end
@@ -1,152 +1,10 @@
1
+ require "simple-immutable"
2
+
1
3
  module Simple
2
4
  module SQL
3
5
  module Helpers
6
+ # for backwards compatibility
7
+ Immutable = ::Simple::Immutable
4
8
  end
5
9
  end
6
10
  end
7
-
8
- class Simple::SQL::Helpers::Immutable
9
- SELF = self
10
-
11
- # turns an object, which can be a hash or array of hashes, arrays, and scalars
12
- # into an object which you can use to access with dot methods.
13
- def self.create(object, max_depth = 5)
14
- case object
15
- when Array
16
- raise ArgumentError, "Object nested too deep (or inner loop?)" if max_depth < 0
17
-
18
- object.map { |obj| create obj, max_depth - 1 }
19
- when Hash
20
- new(object)
21
- else
22
- object
23
- end
24
- end
25
-
26
- private
27
-
28
- def initialize(hsh)
29
- @hsh = hsh
30
- end
31
-
32
- def method_missing(sym, *args, &block)
33
- if args.empty? && !block
34
- begin
35
- value = @hsh.fetch(sym.to_sym) { @hsh.fetch(sym.to_s) }
36
- return SELF.create(value)
37
- rescue KeyError
38
- # STDERR.puts "Missing attribute #{sym} for Immutable w/#{@hsh.inspect}"
39
- nil
40
- end
41
- end
42
-
43
- super
44
- end
45
-
46
- public
47
-
48
- def respond_to_missing?(method_name, include_private = false)
49
- @hsh.key?(method_name.to_sym) ||
50
- @hsh.key?(method_name.to_s) ||
51
- super
52
- end
53
-
54
- def inspect
55
- "<Immutable: #{@hsh.inspect}>"
56
- end
57
-
58
- def respond_to?(sym)
59
- super || @hsh.key?(sym.to_s) || @hsh.key?(sym.to_sym)
60
- end
61
-
62
- def ==(other)
63
- @hsh == other
64
- end
65
- end
66
-
67
- if $PROGRAM_NAME == __FILE__
68
-
69
- # rubocop:disable Metrics/AbcSize
70
-
71
- require "test-unit"
72
-
73
- class Simple::SQL::Helpers::Immutable::TestCase < Test::Unit::TestCase
74
- Immutable = ::Simple::SQL::Helpers::Immutable
75
-
76
- def hsh
77
- {
78
- a: "a-value",
79
- "b": "b-value",
80
- "child": {
81
- name: "childname",
82
- grandchild: {
83
- name: "grandchildname"
84
- }
85
- },
86
- "children": [
87
- "anna",
88
- "arthur",
89
- {
90
- action: {
91
- keep_your_mouth_shut: true
92
- }
93
- }
94
- ]
95
- }
96
- end
97
-
98
- def immutable
99
- Immutable.create hsh
100
- end
101
-
102
- def test_hash_access
103
- assert_equal "a-value", immutable.a
104
- assert_equal "b-value", immutable.b
105
- end
106
-
107
- def test_comparison
108
- immutable = Immutable.create hsh
109
-
110
- assert_equal immutable, hsh
111
- assert_not_equal({}, immutable)
112
- end
113
-
114
- def test_child_access
115
- child = immutable.child
116
- assert_kind_of(Immutable, child)
117
- assert_equal "childname", immutable.child.name
118
- assert_equal "grandchildname", immutable.child.grandchild.name
119
- end
120
-
121
- def test_array_access
122
- assert_kind_of(Array, immutable.children)
123
- assert_equal 3, immutable.children.length
124
- assert_equal "anna", immutable.children[0]
125
-
126
- assert_kind_of(Immutable, immutable.children[2])
127
- assert_equal true, immutable.children[2].action.keep_your_mouth_shut
128
- end
129
-
130
- def test_base_class
131
- assert_nothing_raised do
132
- immutable.object_id
133
- end
134
- end
135
-
136
- def test_missing_keys
137
- assert_raise(NoMethodError) do
138
- immutable.foo
139
- end
140
- end
141
-
142
- def test_skip_when_args_or_block
143
- assert_raise(NoMethodError) do
144
- immutable.a(1, 2, 3)
145
- end
146
- assert_raise(NoMethodError) do
147
- immutable.a { :dummy }
148
- end
149
- end
150
- end
151
-
152
- end
@@ -1,4 +1,5 @@
1
1
  require_relative "./immutable"
2
+ require "simple/immutable"
2
3
 
3
4
  module Simple::SQL::Helpers::RowConverter
4
5
  SELF = self
@@ -57,7 +58,7 @@ module Simple::SQL::Helpers::RowConverter
57
58
  end
58
59
 
59
60
  class ImmutableConverter < TypeConverter #:nodoc:
60
- Immutable = ::Simple::SQL::Helpers::Immutable
61
+ Immutable = ::Simple::Immutable
61
62
 
62
63
  def build_row_in_target_type(hsh)
63
64
  Immutable.create hsh
@@ -0,0 +1,49 @@
1
+ # This file contains some monkey patches
2
+
3
+ module Simple::SQL::MonkeyPatches
4
+ def self.warn(msg)
5
+ @@warned ||= {}
6
+ return if @@warned[msg]
7
+
8
+ @@warned[msg] = true
9
+
10
+ STDERR.puts "== monkeypatch warning: #{msg}"
11
+ end
12
+ end
13
+
14
+ case ActiveRecord.gem_version.to_s
15
+ when /^4/
16
+ :nop
17
+ when /^5.2/
18
+ unless defined?(ActiveRecord::ConnectionAdapters::ConnectionPool::Reaper)
19
+ raise "Make sure to properly require active-record first"
20
+ end
21
+
22
+ # Rails5 introduced a Reaper which starts a Thread which checks for unused connections. However,
23
+ # these threads are never cleaned up. This monkey patch disables the creation of those threads
24
+ # in the first place, consequently preventing leakage of threads.
25
+ #
26
+ # see see https://github.com/rails/rails/issues/33600 and related commits and issues.
27
+ class ActiveRecord::ConnectionAdapters::ConnectionPool::Reaper
28
+ def run
29
+ return unless frequency && frequency > 0
30
+ Simple::SQL::MonkeyPatches.warn "simple-sql disables reapers for all connection pools, see https://github.com/rails/rails/issues/33600"
31
+ end
32
+ end
33
+
34
+ when /^6/
35
+ unless defined?(ActiveRecord::ConnectionAdapters::ConnectionPool::Reaper)
36
+ raise "Make sure to properly require active-record first"
37
+ end
38
+
39
+ # Rails6 fixes the issue w/reapers leaking threads; by properly cleaning up these threads
40
+ # (or so one hopes after looking at connection_pool.rb). However, in the interest of simple-sql
41
+ # being more or less ActiveRecord agnostic we disable reaping here as well. (Also, that code
42
+ # looks pretty complex to me).
43
+ class ActiveRecord::ConnectionAdapters::ConnectionPool::Reaper
44
+ def run
45
+ return unless frequency && frequency > 0
46
+ Simple::SQL::MonkeyPatches.warn "simple-sql disables reapers for all connection pools, see https://github.com/rails/rails/issues/33600"
47
+ end
48
+ end
49
+ end
@@ -5,6 +5,7 @@ module Simple
5
5
 
6
6
  def version(name)
7
7
  spec = Gem.loaded_specs[name]
8
+ return "unreleased" unless spec
8
9
  version = spec.version.to_s
9
10
  version += "+unreleased" if unreleased?(spec)
10
11
  version
data/simple-sql.gemspec CHANGED
@@ -28,6 +28,7 @@ Gem::Specification.new do |gem|
28
28
  gem.add_dependency 'expectation', '~> 1'
29
29
 
30
30
  gem.add_dependency 'digest-crc', '~> 0'
31
+ gem.add_dependency 'simple-immutable', '~> 1.0'
31
32
 
32
33
  # during tests we check the SIMPLE_SQL_ACTIVERECORD_SPECS environment setting.
33
34
  # Run make tests to run all tests
@@ -23,6 +23,7 @@ describe "Simple::SQL conversions" do
23
23
  expects "foo,\"bar}", "SELECT $1::varchar", "foo,\"bar}"
24
24
  expects ["one", "two", "3.5", "foo,\"bar}"], "SELECT ARRAY['one', 'two', '3.5', 'foo,\"bar}']"
25
25
  expects ["foo", "foo,bar}"], "SELECT $1::varchar[]", ["foo", "foo,bar}"]
26
+ expects "foo'bar", 'SELECT $1', "foo'bar"
26
27
  end
27
28
 
28
29
  it "parses JSON as expected" do
@@ -42,13 +43,15 @@ describe "Simple::SQL conversions" do
42
43
  it "converts hstore" do
43
44
  expects({ a: "1", b: "3" }, "SELECT 'a=>1,b=>3'::hstore")
44
45
  end
45
-
46
- xit "fails sometimes w/ malformed array literal, pt. 1" do
47
- expects 0, 'SELECT $1::varchar[]', [ "foo", 'foo,"bar}' ]
48
- end
49
-
50
- xit "fails sometimes w/ malformed array literal, pt. 2" do
51
- expects 0, 'SELECT $1::varchar[]', [ "foo", 'foo,"bar}' ]
46
+ end
47
+
48
+ describe "arra conversions" do
49
+ it "works with strings" do
50
+ expects [ "foo", "bar" ], 'SELECT $1::varchar[]', [ "foo", "bar" ]
51
+
52
+ # test escaping
53
+ expects [ "foo", "foo'bar\"baz" ], 'SELECT $1::varchar[]', [ "foo", "foo'bar\"baz" ]
54
+ expects [ ], 'SELECT $1::varchar[]', []
52
55
  end
53
56
  end
54
57
  end
@@ -61,7 +61,7 @@ describe "Simple::SQL.each" do
61
61
 
62
62
  expect(received.first.id).to eq(1)
63
63
  expect(received[1].dupe).to eq(2)
64
- expect(received.map(&:class).uniq).to eq([Simple::SQL::Helpers::Immutable])
64
+ expect(received.map(&:class).uniq).to eq([Simple::Immutable])
65
65
  end
66
66
  end
67
67
  end
data/spec/spec_helper.rb CHANGED
@@ -6,7 +6,7 @@ end
6
6
  ENV["RACK_ENV"] = "test"
7
7
  ENV["RAILS_ENV"] = "test"
8
8
 
9
- require "byebug"
9
+ require "pry-byebug"
10
10
  require "rspec"
11
11
 
12
12
  Dir.glob("./spec/support/**/*.rb").sort.each { |path| load path }
@@ -1,5 +1,9 @@
1
1
  # connect to the database and setup the schema
2
2
  require "active_record"
3
+
4
+ # it is important to require simple-sql here to activate monkey patches
5
+ require "simple-sql"
6
+
3
7
  require "yaml"
4
8
  abc = YAML.load_file("config/database.yml")
5
9
  ActiveRecord::Base.establish_connection(abc["test"])
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-sql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.27
4
+ version: 0.5.32
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
8
8
  - mediapeers GmbH
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-01-22 00:00:00.000000000 Z
12
+ date: 2021-02-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pg_array_parser
@@ -73,6 +73,20 @@ dependencies:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: simple-immutable
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
76
90
  - !ruby/object:Gem::Dependency
77
91
  name: activerecord
78
92
  requirement: !ruby/object:Gem::Requirement
@@ -171,6 +185,7 @@ extra_rdoc_files: []
171
185
  files:
172
186
  - ".gitignore"
173
187
  - ".rubocop.yml"
188
+ - ".ruby-version"
174
189
  - ".tm_properties"
175
190
  - Gemfile
176
191
  - Makefile
@@ -212,6 +227,7 @@ files:
212
227
  - lib/simple/sql/helpers/immutable.rb
213
228
  - lib/simple/sql/helpers/row_converter.rb
214
229
  - lib/simple/sql/logging.rb
230
+ - lib/simple/sql/monkey_patches.rb
215
231
  - lib/simple/sql/result.rb
216
232
  - lib/simple/sql/result/association_loader.rb
217
233
  - lib/simple/sql/result/records.rb
@@ -256,7 +272,7 @@ files:
256
272
  homepage: http://github.com/radiospiel/simple-sql
257
273
  licenses: []
258
274
  metadata: {}
259
- post_install_message:
275
+ post_install_message:
260
276
  rdoc_options: []
261
277
  require_paths:
262
278
  - lib
@@ -271,8 +287,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
271
287
  - !ruby/object:Gem::Version
272
288
  version: '0'
273
289
  requirements: []
274
- rubygems_version: 3.0.6
275
- signing_key:
290
+ rubygems_version: 3.1.4
291
+ signing_key:
276
292
  specification_version: 4
277
293
  summary: SQL with a simple interface
278
294
  test_files: