simple-sql 0.5.26 → 0.5.31

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: 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