mini_sql 0.3 → 1.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: 3ea4564f53848c314c76c45db0c2af652c1e128ebfc1ba52d6ae11b3799149f4
4
- data.tar.gz: ecdfdc07fdf11e60338bc2ceb0415cbcc027720c5bba645281217a51befc2402
3
+ metadata.gz: 3d668e0b456e27a572040825399ca9477d6c4404bfc09e6e87b1330a106491a0
4
+ data.tar.gz: 3fb2027b34d3837e06f6c92b7075f8811296c0750c5c4c3ae48d6053189a4000
5
5
  SHA512:
6
- metadata.gz: 76a040187f4932dc9fbc80ae3323633a38462753caec47233dbfad3e276e90d8eeb0fbddcbfe974ade3b0b99c18a487d5ef865ebdb1effc67048352ecd35d99d
7
- data.tar.gz: 73c3519bf51a7934af89827830e3e7c45366eec01b1d65dc0c61afb2b87c12b093e9f3db99b1c4db081e6a6a1e983fd24d88db3aa13f63b9e546af0dce36beae
6
+ metadata.gz: 60449b0a92a13aa471dbc1dd6db2b8ba0571bca67f81bd46644bf8678ab794b5447e59cd3ea7a24d4732bcdb8eca44c9dfec748c57418d826444305395f62190
7
+ data.tar.gz: a249f769da221d659d1b4dceaf3dd153578fbda3f0951bdac938d178923a54ad852106629d76be38b5c4ad83c4175592b9971223f8e0aab49e91a48747ad7148
@@ -0,0 +1,66 @@
1
+ name: Mini SQL Tests
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - master
8
+
9
+ env:
10
+ PGHOST: localhost
11
+ PGPORT: 5432
12
+ PGPASSWORD: postgres
13
+ PGUSER: postgres
14
+ MINI_SQL_MYSQL_HOST: 127.0.0.1
15
+ MINI_SQL_MYSQL_PORT: 3306
16
+ MINI_SQL_MYSQL_PASSWORD: mysql
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ name: Ruby ${{ matrix.ruby }}
21
+ services:
22
+ postgres:
23
+ image: postgres:9.6
24
+ env:
25
+ POSTGRES_PASSWORD: postgres
26
+ ports:
27
+ - 5432:5432
28
+ options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
29
+ mysql:
30
+ image: mysql:5.7
31
+ env:
32
+ MYSQL_ROOT_PASSWORD: mysql
33
+ ports:
34
+ - 3306:3306
35
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
36
+ strategy:
37
+ matrix:
38
+ ruby: ["2.7", "2.6", "2.5"]
39
+ experimental: [false]
40
+ include:
41
+ - ruby: ruby-head
42
+ experimental: true
43
+ steps:
44
+ - uses: actions/checkout@v2
45
+ - uses: ruby/setup-ruby@v1
46
+ with:
47
+ ruby-version: ${{ matrix.ruby }}
48
+ - name: Bundler cache
49
+ uses: actions/cache@v2
50
+ with:
51
+ path: vendor/bundle
52
+ key: ${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles('**/Gemfile.lock') }}
53
+ restore-keys: |
54
+ ${{ runner.os }}-${{ matrix.ruby }}-gems-
55
+ - name: Create Databases
56
+ run: |
57
+ createdb test_mini_sql
58
+ mysql --host=127.0.0.1 --port=3306 --user=root --password=mysql -e 'CREATE DATABASE test_mini_sql'
59
+ - name: Setup gems
60
+ run: |
61
+ bundle config path vendor/bundle
62
+ bundle install --jobs 4
63
+ - name: Tests
64
+ run: bundle exec rake test
65
+ - name: Rubocop
66
+ run: bundle exec rubocop
@@ -1,5 +1,8 @@
1
- inherit_from: https://raw.githubusercontent.com/discourse/discourse/master/.rubocop.yml
2
-
1
+ inherit_gem:
2
+ rubocop-discourse: default.yml
3
+ inherit_mode:
4
+ merge:
5
+ - Exclude
3
6
  AllCops:
4
7
  Exclude:
5
8
  - 'bench/**/*'
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ 2020-12-30 - 1.0
2
+
3
+ - Added serialization support using MiniSql::Serializer.to_json / .from_json
4
+ - Fixed minor issue with cache poisoning when using query_decorator
5
+ - Version 1.0 to reflect the stability of the interfaces and project, used in productions for almost 2 years now
6
+
1
7
  2020-06-25 - 0.3
2
8
 
3
9
  - Added support for query_each and query_each_hash, which lazily queries rows and enables selecting large result sets by streaming
@@ -8,6 +8,9 @@ require_relative "mini_sql/connection"
8
8
  require_relative "mini_sql/deserializer_cache"
9
9
  require_relative "mini_sql/builder"
10
10
  require_relative "mini_sql/inline_param_encoder"
11
+ require_relative "mini_sql/decoratable"
12
+ require_relative "mini_sql/serializer"
13
+ require_relative "mini_sql/result"
11
14
 
12
15
  module MiniSql
13
16
  if RUBY_ENGINE == 'jruby'
@@ -66,4 +66,14 @@ class MiniSql::Builder
66
66
  RUBY
67
67
  end
68
68
 
69
+ def query_decorator(decorator, hash_args = nil)
70
+ hash_args = @args.merge(hash_args) if hash_args && @args
71
+ hash_args ||= @args
72
+ if hash_args
73
+ @connection.query_decorator(decorator, to_sql, hash_args)
74
+ else
75
+ @connection.query_decorator(decorator, to_sql)
76
+ end
77
+ end
78
+
69
79
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniSql
4
+ module Decoratable
5
+ def decorated(mod)
6
+ @decoratorated_classes ||= {}
7
+ @decoratorated_classes[mod] ||=
8
+ Class.new(self) do
9
+ include(mod)
10
+ instance_eval <<~RUBY
11
+ def decorator
12
+ #{mod}
13
+ end
14
+ RUBY
15
+ end
16
+ end
17
+
18
+ def decorator
19
+ nil
20
+ end
21
+ end
22
+ end
@@ -50,9 +50,7 @@ module MiniSql
50
50
  private
51
51
 
52
52
  def run(sql, as, params)
53
- if params && params.length > 0
54
- sql = param_encoder.encode(sql, *params)
55
- end
53
+ sql = param_encoder.encode(sql, *params)
56
54
  raw_connection.query(
57
55
  sql,
58
56
  as: as,
@@ -23,7 +23,9 @@ module MiniSql
23
23
  @cache.shift if @cache.length > @max_size
24
24
  end
25
25
 
26
- materializer.include(decorator_module) if decorator_module
26
+ if decorator_module
27
+ materializer = materializer.decorated(decorator_module)
28
+ end
27
29
 
28
30
  result.map do |data|
29
31
  materializer.materialize(data)
@@ -36,18 +38,10 @@ module MiniSql
36
38
  fields = result.fields
37
39
 
38
40
  Class.new do
39
- attr_accessor(*fields)
40
-
41
- # AM serializer support
42
- alias :read_attribute_for_serialization :send
41
+ extend MiniSql::Decoratable
42
+ include MiniSql::Result
43
43
 
44
- def to_h
45
- r = {}
46
- instance_variables.each do |f|
47
- r[f.to_s.sub('@', '').to_sym] = instance_variable_get(f)
48
- end
49
- r
50
- end
44
+ attr_accessor(*fields)
51
45
 
52
46
  instance_eval <<~RUBY
53
47
  def materialize(data)
@@ -84,7 +84,7 @@ module MiniSql
84
84
  result.type_map = type_map
85
85
  result.values
86
86
  ensure
87
- result.clear if result
87
+ result.clear if result
88
88
  end
89
89
 
90
90
  def query(sql, *params)
@@ -97,9 +97,7 @@ module MiniSql
97
97
 
98
98
  def query_each(sql, *params)
99
99
  raise StandardError, "Please supply a block when calling query_each" if !block_given?
100
- if params && params.length > 0
101
- sql = param_encoder.encode(sql, *params)
102
- end
100
+ sql = param_encoder.encode(sql, *params)
103
101
 
104
102
  raw_connection.send_query(sql)
105
103
  raw_connection.set_single_row_mode
@@ -130,9 +128,7 @@ module MiniSql
130
128
 
131
129
  def query_each_hash(sql, *params)
132
130
  raise StandardError, "Please supply a block when calling query_each_hash" if !block_given?
133
- if params && params.length > 0
134
- sql = param_encoder.encode(sql, *params)
135
- end
131
+ sql = param_encoder.encode(sql, *params)
136
132
 
137
133
  raw_connection.send_query(sql)
138
134
  raw_connection.set_single_row_mode
@@ -195,9 +191,7 @@ module MiniSql
195
191
  private
196
192
 
197
193
  def run(sql, params)
198
- if params && params.length > 0
199
- sql = param_encoder.encode(sql, *params)
200
- end
194
+ sql = param_encoder.encode(sql, *params)
201
195
  raw_connection.async_exec(sql)
202
196
  end
203
197
 
@@ -39,7 +39,9 @@ module MiniSql
39
39
  @cache.shift if @cache.length > @max_size
40
40
  end
41
41
 
42
- materializer.include(decorator_module) if decorator_module
42
+ if decorator_module
43
+ materializer = materializer.decorated(decorator_module)
44
+ end
43
45
 
44
46
  i = 0
45
47
  r = []
@@ -66,18 +68,10 @@ module MiniSql
66
68
  end
67
69
 
68
70
  Class.new do
69
- attr_accessor(*fields)
70
-
71
- # AM serializer support
72
- alias :read_attribute_for_serialization :send
71
+ extend MiniSql::Decoratable
72
+ include MiniSql::Result
73
73
 
74
- def to_h
75
- r = {}
76
- instance_variables.each do |f|
77
- r[f.to_s.sub('@', '').to_sym] = instance_variable_get(f)
78
- end
79
- r
80
- end
74
+ attr_accessor(*fields)
81
75
 
82
76
  instance_eval <<~RUBY
83
77
  def materialize(pg_result, index)
@@ -89,7 +89,7 @@ module MiniSql
89
89
  private
90
90
 
91
91
  def run(sql, params)
92
- sql = param_encoder.encode(sql, *params) if params && params.length > 0
92
+ sql = param_encoder.encode(sql, *params)
93
93
  conn = raw_connection
94
94
  conn.typemap = self.class.typemap
95
95
  conn.execute(sql)
@@ -28,6 +28,10 @@ module MiniSql
28
28
 
29
29
  materializer.include(decorator_module) if decorator_module
30
30
 
31
+ if decorator_module
32
+ materializer = materializer.decorated(decorator_module)
33
+ end
34
+
31
35
  i = 0
32
36
  r = []
33
37
  # quicker loop
@@ -44,18 +48,10 @@ module MiniSql
44
48
  fields = result.fields
45
49
 
46
50
  Class.new do
47
- attr_accessor(*fields)
51
+ extend MiniSql::Decoratable
52
+ include MiniSql::Result
48
53
 
49
- # AM serializer support
50
- alias :read_attribute_for_serialization :send
51
-
52
- def to_h
53
- r = {}
54
- instance_variables.each do |f|
55
- r[f.to_s.sub('@', '').to_sym] = instance_variable_get(f)
56
- end
57
- r
58
- end
54
+ attr_accessor(*fields)
59
55
 
60
56
  instance_eval <<~RUBY
61
57
  def materialize(pg_result, index)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniSql
4
+ module Result
5
+ # AM serializer support
6
+ alias :read_attribute_for_serialization :send
7
+
8
+ def to_h
9
+ r = {}
10
+ instance_variables.each do |f|
11
+ r[f.to_s.delete_prefix('@').to_sym] = instance_variable_get(f)
12
+ end
13
+ r
14
+ end
15
+
16
+ def values
17
+ instance_variables.map { |f| instance_variable_get(f) }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniSql
4
+ module Serializer
5
+ MAX_CACHE_SIZE = 500
6
+
7
+ def self.to_json(result)
8
+ wrapper =
9
+ if result.length == 0
10
+ {}
11
+ else
12
+ {
13
+ "decorator" => result[0].class.decorator.to_s,
14
+ "fields" => result[0].to_h.keys,
15
+ "data" => result.map(&:values),
16
+ }
17
+ end
18
+
19
+ JSON.generate(wrapper)
20
+ end
21
+
22
+ def self.from_json(json)
23
+ wrapper = JSON.parse(json)
24
+ if !wrapper["data"]
25
+ []
26
+ else
27
+ materializer = cached_materializer(wrapper['fields'], wrapper['decorator'])
28
+ wrapper["data"].map do |row|
29
+ materializer.materialize(row)
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.cached_materializer(fields, decorator_module = nil)
35
+ @cache ||= {}
36
+ key = fields
37
+ m = @cache.delete(key)
38
+ if m
39
+ @cache[key] = m
40
+ else
41
+ m = @cache[key] = materializer(fields)
42
+ @cache.shift if @cache.length > MAX_CACHE_SIZE
43
+ end
44
+
45
+ if decorator_module && decorator_module.length > 0
46
+ decorator = Kernel.const_get(decorator_module)
47
+ m = m.decorated(decorator)
48
+ end
49
+
50
+ m
51
+ end
52
+
53
+ def self.materializer(fields)
54
+ Class.new do
55
+ extend MiniSql::Decoratable
56
+ include MiniSql::Result
57
+
58
+ attr_accessor(*fields)
59
+
60
+ instance_eval <<~RUBY
61
+ def materialize(values)
62
+ r = self.new
63
+ #{col = -1; fields.map { |f| "r.#{f} = values[#{col += 1}]" }.join("; ")}
64
+ r
65
+ end
66
+ RUBY
67
+ end
68
+ end
69
+ end
70
+ end
@@ -63,9 +63,7 @@ module MiniSql
63
63
  private
64
64
 
65
65
  def run(sql, *params)
66
- if params && params.length > 0
67
- sql = param_encoder.encode(sql, *params)
68
- end
66
+ sql = param_encoder.encode(sql, *params)
69
67
  if block_given?
70
68
  stmt = SQLite3::Statement.new(raw_connection, sql)
71
69
  yield stmt.execute
@@ -24,7 +24,9 @@ module MiniSql
24
24
  @cache.shift if @cache.length > @max_size
25
25
  end
26
26
 
27
- materializer.include(decorator_module) if decorator_module
27
+ if decorator_module
28
+ materializer = materializer.decorated(decorator_module)
29
+ end
28
30
 
29
31
  r = []
30
32
  # quicker loop
@@ -43,18 +45,10 @@ module MiniSql
43
45
  fields = result.columns
44
46
 
45
47
  Class.new do
46
- attr_accessor(*fields)
47
-
48
- # AM serializer support
49
- alias :read_attribute_for_serialization :send
48
+ extend MiniSql::Decoratable
49
+ include MiniSql::Result
50
50
 
51
- def to_h
52
- r = {}
53
- instance_variables.each do |f|
54
- r[f.to_s.sub('@', '').to_sym] = instance_variable_get(f)
55
- end
56
- r
57
- end
51
+ attr_accessor(*fields)
58
52
 
59
53
  instance_eval <<~RUBY
60
54
  def materialize(data)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module MiniSql
3
- VERSION = "0.3"
3
+ VERSION = "1.0"
4
4
  end
@@ -25,11 +25,11 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  # Specify which files should be added to the gem when it is released.
27
27
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
28
- # rubocop:disable DiscoruseCops/NoChdir
28
+ # rubocop:disable Discourse/NoChdir
29
29
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
30
30
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
31
31
  end
32
- # rubocop:enable DiscoruseCops/NoChdir
32
+ # rubocop:enable Discourse/NoChdir
33
33
  spec.require_paths = ["lib"]
34
34
 
35
35
  spec.add_development_dependency "bundler", "> 1.16"
@@ -38,8 +38,9 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency "guard", "~> 2.14"
39
39
  spec.add_development_dependency "guard-minitest", "~> 2.4"
40
40
  spec.add_development_dependency "activesupport", "~> 5.2"
41
- spec.add_development_dependency 'rubocop', '~> 0.79.0'
42
- spec.add_development_dependency 'rubocop-discourse', '~> 1.0.2'
41
+ spec.add_development_dependency 'rubocop', '~> 1.4.0'
42
+ spec.add_development_dependency 'rubocop-discourse', '~> 2.4.1'
43
+ spec.add_development_dependency 'm', '~> 1.5.1'
43
44
 
44
45
  if RUBY_ENGINE == 'jruby'
45
46
  spec.add_development_dependency "activerecord-jdbcpostgresql-adapter", "~> 52.2"
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: '0.3'
4
+ version: '1.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: 2020-06-25 00:00:00.000000000 Z
11
+ date: 2020-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -100,28 +100,42 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 0.79.0
103
+ version: 1.4.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 0.79.0
110
+ version: 1.4.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rubocop-discourse
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 1.0.2
117
+ version: 2.4.1
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 1.0.2
124
+ version: 2.4.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: m
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 1.5.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 1.5.1
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: pg
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -171,10 +185,10 @@ executables: []
171
185
  extensions: []
172
186
  extra_rdoc_files: []
173
187
  files:
188
+ - ".github/workflows/ci.yml"
174
189
  - ".gitignore"
175
190
  - ".rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml"
176
191
  - ".rubocop.yml"
177
- - ".travis.yml"
178
192
  - CHANGELOG
179
193
  - CODE_OF_CONDUCT.md
180
194
  - Gemfile
@@ -190,6 +204,7 @@ files:
190
204
  - lib/mini_sql.rb
191
205
  - lib/mini_sql/builder.rb
192
206
  - lib/mini_sql/connection.rb
207
+ - lib/mini_sql/decoratable.rb
193
208
  - lib/mini_sql/deserializer_cache.rb
194
209
  - lib/mini_sql/inline_param_encoder.rb
195
210
  - lib/mini_sql/mysql/connection.rb
@@ -199,6 +214,8 @@ files:
199
214
  - lib/mini_sql/postgres/deserializer_cache.rb
200
215
  - lib/mini_sql/postgres_jdbc/connection.rb
201
216
  - lib/mini_sql/postgres_jdbc/deserializer_cache.rb
217
+ - lib/mini_sql/result.rb
218
+ - lib/mini_sql/serializer.rb
202
219
  - lib/mini_sql/sqlite/connection.rb
203
220
  - lib/mini_sql/sqlite/deserializer_cache.rb
204
221
  - lib/mini_sql/version.rb
@@ -225,7 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
242
  - !ruby/object:Gem::Version
226
243
  version: '0'
227
244
  requirements: []
228
- rubygems_version: 3.0.3
245
+ rubygems_version: 3.2.3
229
246
  signing_key:
230
247
  specification_version: 4
231
248
  summary: A fast, safe, simple direct SQL executor
@@ -1,28 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.5
4
- - 2.6
5
- - 2.7
6
- - ruby-head
7
-
8
- before_install:
9
- - gem install bundler
10
-
11
- cache: bundler
12
- sudo: false
13
-
14
- services:
15
- - mysql
16
-
17
- addons:
18
- postgresql: 9.6
19
- mysql: 5.7
20
-
21
- install:
22
- - createdb test_mini_sql
23
- - mysql -e 'CREATE DATABASE test_mini_sql;'
24
- - bundle install
25
-
26
- matrix:
27
- allow_failures:
28
- - rvm: ruby-head