simple-sql 0.5.26 → 0.5.31

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: fab09e2181d6826802076b03cf71b0c742862ab1bf58e730403eee0eed1bb1c6
4
- data.tar.gz: 4f64d6025f76fec82d72f83cc936072cb092fa51f5fa0ad4ea37da1e70b045a3
3
+ metadata.gz: 7490b50fc301d6e1a8c424e46a21f4a5cb97767ca2a99c7bdeed94b7c499a0d6
4
+ data.tar.gz: 3e1ec456a008d2abee6260b84beb1c17ca4b5934c1b934f00298ad6263b0f849
5
5
  SHA512:
6
- metadata.gz: e8d383d973a2564e5e841e3820c24dc8aa9438c1ce3629f9508538e53c9775ef9ec16e8b7979933d1fed09bdc9389c71b2ce31122347f096f0e604bba2b20184
7
- data.tar.gz: 8a8caf53d1e973c8d762e725e7a7f91ea2fc5295d092c024db4227bda1c92976b0600f1f62d80d1d98794b5f35dc0eea3639ef887dbb2506b1cfdf20b8d7a055
6
+ metadata.gz: 5c4ff2ac25d314393ff79a5f8ff3171508b05f30a99f37d1681a5b4af0fe3f07f247623321e235fc70de4d384d8e994935fc69eaf592c41b8459ceb0c875adf7
7
+ data.tar.gz: e59f00c7d6a3f00d1f4c2ca101985e8a01b453cc80b774f5f95b867eebea3e1dddf70a341fd4bf8904e497b19738d58e2a66d20a08372a138bf2302d918af1cb
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.26
1
+ 0.5.31
@@ -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
 
@@ -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
@@ -75,6 +75,12 @@ module Simple::SQL::Connection::Scope::Search
75
75
 
76
76
  # -- apply dynamic filters --------------------------------------------------
77
77
 
78
+ def empty_filter?(_key, value)
79
+ return true if value.nil?
80
+ return true if value.is_a?(Enumerable) && value.empty? # i.e. Hash, Array
81
+ false
82
+ end
83
+
78
84
  def apply_dynamic_filters(scope, filters, dynamic_column:)
79
85
  # we translate a condition of "foo => []" into a SQL fragment like this:
80
86
  #
@@ -82,7 +88,7 @@ module Simple::SQL::Connection::Scope::Search
82
88
  #
83
89
  # i.e. we check for non-existing columns and columns that exist but have a
84
90
  # value of null (i.e. column->'key' IS NULL).
85
- empty_filters, filters = filters.partition { |_key, value| value.nil? || value.empty? }
91
+ empty_filters, filters = filters.partition { |key, value| empty_filter?(key, value) }
86
92
  empty_filters.each do |key, _|
87
93
  scope = scope.where("(NOT #{dynamic_column} ? '#{key}' OR #{dynamic_column} @> '#{::JSON.generate(key => nil)}'::jsonb)")
88
94
  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
@@ -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
@@ -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
@@ -20,10 +20,14 @@ describe "Simple::SQL.search" do
20
20
  scope.search(*args).all
21
21
  end
22
22
 
23
- it "filters by one dynamic attribute and one match" do
23
+ it "filters by one dynamic attribute matching a String" do
24
24
  expect(search(even_str: "yes").map(&:id)).to contain_exactly(2,4,6,8,10)
25
25
  end
26
26
 
27
+ it "filters by one dynamic attribute matching an Integer" do
28
+ expect(search(user_id_squared: 4).map(&:id)).to contain_exactly(2)
29
+ end
30
+
27
31
  it "filters by one dynamic attribute and multiple matches" do
28
32
  expect(search(user_id_squared: [1, 3, 9]).map(&:id)).to contain_exactly(1,3)
29
33
  end
@@ -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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-sql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.26
4
+ version: 0.5.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-01-21 00:00:00.000000000 Z
12
+ date: 2020-09-04 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
@@ -212,6 +226,7 @@ files:
212
226
  - lib/simple/sql/helpers/immutable.rb
213
227
  - lib/simple/sql/helpers/row_converter.rb
214
228
  - lib/simple/sql/logging.rb
229
+ - lib/simple/sql/monkey_patches.rb
215
230
  - lib/simple/sql/result.rb
216
231
  - lib/simple/sql/result/association_loader.rb
217
232
  - lib/simple/sql/result/records.rb