yesql 0.1.2 → 0.1.7

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: 731e003db09b7b0113cb2e2be02d5e0bc78a4882d8c76afdee1d1555145e3d35
4
- data.tar.gz: 3aab0521aaff1265417693f8e527b44055ffe39a4e9268fe9997f97a5449c85b
3
+ metadata.gz: 180f75c325ecfc85f0d95e0d0a9422fcde92db273487bd19a7f03318c3206f16
4
+ data.tar.gz: '00429a2c7880d6546e82b5c530d097be14e524ed161a81d7c75b55c61f86f2b7'
5
5
  SHA512:
6
- metadata.gz: 39acb84f1659f7231431cfb67ad703922042da97057aa54d282f711fc2aaebe3b4f62b2220c4f994008cbb0764f71703e9d32c86ffe6dcabc869e7cc0bc4485b
7
- data.tar.gz: 8fcdeac79b914101f18e56b548be2f58657a0df2b8b21d182e959cf11f960e6bf3c0ca7096b0df3f29ca6c85876cc295756887b9435ee222922fb2f55c1c5a77
6
+ metadata.gz: 6a13774afd3b568927652026d00ac25d1b521c4eebcdcf4d2f4bc9d3de86652613322d449e30f276eabfebcb2aaa044bdc66abc3757f0f759533b0fcf5c53868
7
+ data.tar.gz: 3017fb1e072485f1c3d469517c1e326d74c32f2d14873a8801c78da8d0bb1f49459a81f6abc64b9c0fa1680dd8799cd12328496ec0077fa2823e24e204f80c1a
@@ -0,0 +1,4 @@
1
+ spec/minimalpg/log/*
2
+ spec/minimalmysql/log/*
3
+ spec/minimalpg/db/*
4
+ spec/minimalmysql/db/*
@@ -0,0 +1,20 @@
1
+ require: rubocop-rspec
2
+
3
+ Metrics/BlockLength:
4
+ Exclude:
5
+ - spec/**/*_spec.rb
6
+ - spec/spec_helper.rb
7
+ - spec/yesql/shared/*
8
+
9
+ RSpec/FilePath:
10
+ Exclude:
11
+ - spec/**/*_spec.rb
12
+
13
+ RSpec/NestedGroups:
14
+ Enabled: False
15
+
16
+ RSpec/ExampleLength:
17
+ Enabled: False
18
+
19
+ RSpec/BeforeAfterAll:
20
+ Enabled: False
@@ -1,63 +1,62 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yesql (0.1.0)
5
- dry-configurable (~> 0.11.6)
4
+ yesql (0.1.6)
6
5
  rails (>= 5.0)
7
6
 
8
7
  GEM
9
8
  remote: https://rubygems.org/
10
9
  specs:
11
- actioncable (6.0.3.3)
12
- actionpack (= 6.0.3.3)
10
+ actioncable (6.0.3.4)
11
+ actionpack (= 6.0.3.4)
13
12
  nio4r (~> 2.0)
14
13
  websocket-driver (>= 0.6.1)
15
- actionmailbox (6.0.3.3)
16
- actionpack (= 6.0.3.3)
17
- activejob (= 6.0.3.3)
18
- activerecord (= 6.0.3.3)
19
- activestorage (= 6.0.3.3)
20
- activesupport (= 6.0.3.3)
14
+ actionmailbox (6.0.3.4)
15
+ actionpack (= 6.0.3.4)
16
+ activejob (= 6.0.3.4)
17
+ activerecord (= 6.0.3.4)
18
+ activestorage (= 6.0.3.4)
19
+ activesupport (= 6.0.3.4)
21
20
  mail (>= 2.7.1)
22
- actionmailer (6.0.3.3)
23
- actionpack (= 6.0.3.3)
24
- actionview (= 6.0.3.3)
25
- activejob (= 6.0.3.3)
21
+ actionmailer (6.0.3.4)
22
+ actionpack (= 6.0.3.4)
23
+ actionview (= 6.0.3.4)
24
+ activejob (= 6.0.3.4)
26
25
  mail (~> 2.5, >= 2.5.4)
27
26
  rails-dom-testing (~> 2.0)
28
- actionpack (6.0.3.3)
29
- actionview (= 6.0.3.3)
30
- activesupport (= 6.0.3.3)
27
+ actionpack (6.0.3.4)
28
+ actionview (= 6.0.3.4)
29
+ activesupport (= 6.0.3.4)
31
30
  rack (~> 2.0, >= 2.0.8)
32
31
  rack-test (>= 0.6.3)
33
32
  rails-dom-testing (~> 2.0)
34
33
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
35
- actiontext (6.0.3.3)
36
- actionpack (= 6.0.3.3)
37
- activerecord (= 6.0.3.3)
38
- activestorage (= 6.0.3.3)
39
- activesupport (= 6.0.3.3)
34
+ actiontext (6.0.3.4)
35
+ actionpack (= 6.0.3.4)
36
+ activerecord (= 6.0.3.4)
37
+ activestorage (= 6.0.3.4)
38
+ activesupport (= 6.0.3.4)
40
39
  nokogiri (>= 1.8.5)
41
- actionview (6.0.3.3)
42
- activesupport (= 6.0.3.3)
40
+ actionview (6.0.3.4)
41
+ activesupport (= 6.0.3.4)
43
42
  builder (~> 3.1)
44
43
  erubi (~> 1.4)
45
44
  rails-dom-testing (~> 2.0)
46
45
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
47
- activejob (6.0.3.3)
48
- activesupport (= 6.0.3.3)
46
+ activejob (6.0.3.4)
47
+ activesupport (= 6.0.3.4)
49
48
  globalid (>= 0.3.6)
50
- activemodel (6.0.3.3)
51
- activesupport (= 6.0.3.3)
52
- activerecord (6.0.3.3)
53
- activemodel (= 6.0.3.3)
54
- activesupport (= 6.0.3.3)
55
- activestorage (6.0.3.3)
56
- actionpack (= 6.0.3.3)
57
- activejob (= 6.0.3.3)
58
- activerecord (= 6.0.3.3)
49
+ activemodel (6.0.3.4)
50
+ activesupport (= 6.0.3.4)
51
+ activerecord (6.0.3.4)
52
+ activemodel (= 6.0.3.4)
53
+ activesupport (= 6.0.3.4)
54
+ activestorage (6.0.3.4)
55
+ actionpack (= 6.0.3.4)
56
+ activejob (= 6.0.3.4)
57
+ activerecord (= 6.0.3.4)
59
58
  marcel (~> 0.3.1)
60
- activesupport (6.0.3.3)
59
+ activesupport (6.0.3.4)
61
60
  concurrent-ruby (~> 1.0, >= 1.0.2)
62
61
  i18n (>= 0.7, < 2)
63
62
  minitest (~> 5.1)
@@ -68,13 +67,6 @@ GEM
68
67
  concurrent-ruby (1.1.7)
69
68
  crass (1.0.6)
70
69
  diff-lcs (1.4.4)
71
- dry-configurable (0.11.6)
72
- concurrent-ruby (~> 1.0)
73
- dry-core (~> 0.4, >= 0.4.7)
74
- dry-equalizer (~> 0.2)
75
- dry-core (0.4.9)
76
- concurrent-ruby (~> 1.0)
77
- dry-equalizer (0.3.0)
78
70
  erubi (1.9.0)
79
71
  globalid (0.4.2)
80
72
  activesupport (>= 4.2.0)
@@ -92,7 +84,8 @@ GEM
92
84
  mini_mime (1.0.2)
93
85
  mini_portile2 (2.4.0)
94
86
  minitest (5.14.2)
95
- nio4r (2.5.3)
87
+ mysql2 (0.5.3)
88
+ nio4r (2.5.4)
96
89
  nokogiri (1.10.10)
97
90
  mini_portile2 (~> 2.4.0)
98
91
  pg (1.2.3)
@@ -102,29 +95,29 @@ GEM
102
95
  rack (2.2.3)
103
96
  rack-test (1.1.0)
104
97
  rack (>= 1.0, < 3)
105
- rails (6.0.3.3)
106
- actioncable (= 6.0.3.3)
107
- actionmailbox (= 6.0.3.3)
108
- actionmailer (= 6.0.3.3)
109
- actionpack (= 6.0.3.3)
110
- actiontext (= 6.0.3.3)
111
- actionview (= 6.0.3.3)
112
- activejob (= 6.0.3.3)
113
- activemodel (= 6.0.3.3)
114
- activerecord (= 6.0.3.3)
115
- activestorage (= 6.0.3.3)
116
- activesupport (= 6.0.3.3)
98
+ rails (6.0.3.4)
99
+ actioncable (= 6.0.3.4)
100
+ actionmailbox (= 6.0.3.4)
101
+ actionmailer (= 6.0.3.4)
102
+ actionpack (= 6.0.3.4)
103
+ actiontext (= 6.0.3.4)
104
+ actionview (= 6.0.3.4)
105
+ activejob (= 6.0.3.4)
106
+ activemodel (= 6.0.3.4)
107
+ activerecord (= 6.0.3.4)
108
+ activestorage (= 6.0.3.4)
109
+ activesupport (= 6.0.3.4)
117
110
  bundler (>= 1.3.0)
118
- railties (= 6.0.3.3)
111
+ railties (= 6.0.3.4)
119
112
  sprockets-rails (>= 2.0.0)
120
113
  rails-dom-testing (2.0.3)
121
114
  activesupport (>= 4.2.0)
122
115
  nokogiri (>= 1.6)
123
116
  rails-html-sanitizer (1.3.0)
124
117
  loofah (~> 2.3)
125
- railties (6.0.3.3)
126
- actionpack (= 6.0.3.3)
127
- activesupport (= 6.0.3.3)
118
+ railties (6.0.3.4)
119
+ actionpack (= 6.0.3.4)
120
+ activesupport (= 6.0.3.4)
128
121
  method_source
129
122
  rake (>= 0.8.7)
130
123
  thor (>= 0.20.3, < 2.0)
@@ -163,6 +156,7 @@ PLATFORMS
163
156
  ruby
164
157
 
165
158
  DEPENDENCIES
159
+ mysql2 (~> 0.5.3)
166
160
  pg (>= 0.18)
167
161
  pry (~> 0.13.1)
168
162
  rspec (~> 3.9.0)
data/README.md CHANGED
@@ -70,7 +70,6 @@ YeSQL('top_10_users_in_x_country', { country: 'Cuba', country_id: 1, limit: 6 })
70
70
  ```
71
71
 
72
72
  - If the query doesn't have bindings, but they're provided they're just omitted.
73
- TODO: update this with link to the error.
74
73
  - If the query has bindings, but nothing is provided, it raises a `NotImplementedError` exception.
75
74
 
76
75
 
@@ -145,21 +144,21 @@ YeSQL('users', cache: { expires_in: 1.hour })
145
144
 
146
145
  ## Configuration
147
146
 
148
- For default `YeSQL` looks for the _.sql_ files defined under the `app/yesql/` folder but you can update it to use any folder you need. For that you can create a Ruby file under the `config/initializers/` folder as:
147
+ For default `YeSQL` looks for the _.sql_ files defined under the `app/yesql/` folder but you can update it to use any folder you need. For that you can create a Ruby file under the `config/initializers/` with the following content:
149
148
 
150
149
  ```ruby
151
- YeSQL.config.path = 'path'
150
+ ::YeSQL.configure { |config| config.path = 'path' }
152
151
  ```
153
152
 
154
153
  After saving the file and restarting the server the files are going to be read from the given folder.
155
154
 
156
- You can check at anytime what's the configuration path by inspecting the YeSQL `config` object:
155
+ You can check at anytime what's the configuration path by inspecting the ::YeSQL `config` object:
157
156
 
158
157
  ```ruby
159
- YeSQL.config
160
- # <Dry::Configurable::Config values={:path=>"path"}>
161
- Yesql.config.path
162
- # "path"
158
+ ::YeSQL.config
159
+ # => #<YeSQL::Config::Configuration:0x00007feea1aa2ef8 @path="app/yesql">
160
+ ::YeSQL.config.path
161
+ # => "app/yesql"
163
162
  ```
164
163
 
165
164
 
@@ -167,7 +166,7 @@ Yesql.config.path
167
166
 
168
167
  - Clone the repository.
169
168
  - Install the gem dependencies.
170
- - Make sure to create the database used in the dummy Rails application in the spec/ folder.
169
+ - Make sure to create both databases used in the dummy Rails applications (mysql, pg) in the spec/ folder.
171
170
  - Run the tests.
172
171
 
173
172
  ## Contributing
@@ -1,25 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-configurable'
4
- require 'pry'
3
+ require 'yesql/statement'
5
4
  require 'yesql/version'
5
+ require 'yesql/config/configuration'
6
6
  require 'yesql/query/performer'
7
7
  require 'yesql/errors/cache_expiration_error'
8
8
  require 'yesql/errors/file_path_does_not_exist_error'
9
9
  require 'yesql/errors/no_bindings_provided_error'
10
10
  require 'yesql/errors/output_argument_error'
11
- require 'yesql/bindings/binder'
12
11
 
13
12
  module YeSQL
14
- extend ::Dry::Configurable
15
-
13
+ include ::YeSQL::Config
16
14
  include ::YeSQL::Errors::CacheExpirationError
17
15
  include ::YeSQL::Errors::FilePathDoesNotExistError
18
16
  include ::YeSQL::Errors::NoBindingsProvidedError
19
17
  include ::YeSQL::Errors::OutputArgumentError
20
18
 
21
- setting :path, 'app/yesql'
22
-
23
19
  BIND_REGEX = /(?<!:):(\w+)(?=\b)/.freeze
24
20
 
25
21
  # rubocop:disable Naming/MethodName
@@ -44,7 +40,7 @@ module YeSQL
44
40
  def execute(bindings, cache, file_path, output, options)
45
41
  ::YeSQL::Query::Performer.new(
46
42
  bindings: bindings,
47
- bind_statement: ::YeSQL::Bindings::Binder.bind_statement(file_path, bindings),
43
+ bind_statement: ::YeSQL::Statement.new(bindings, file_path),
48
44
  cache: cache,
49
45
  file_path: file_path,
50
46
  output: output,
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'yesql'
4
+ require 'yesql/common/adapter'
4
5
 
5
- module YeSQL
6
+ module ::YeSQL
6
7
  module Bindings
7
8
  class Extract
9
+ include ::YeSQL::Common::Adapter
10
+
8
11
  def initialize(indexed_bindings, hash, index, value)
9
12
  @indexed_bindings = indexed_bindings
10
13
  @hash = hash
@@ -19,9 +22,15 @@ module YeSQL
19
22
  end
20
23
 
21
24
  def bind_vars
22
- return "$#{last_val}" unless array?
25
+ if mysql?
26
+ return '?' unless array?
27
+
28
+ Array.new(value.size, '?').join(', ')
29
+ elsif pg?
30
+ return "$#{last_val}" unless array?
23
31
 
24
- value.map.with_index(bind_index) { |_, i| "$#{i}" }.join(', ')
32
+ value.map.with_index(bind_index) { |_, i| "$#{i}" }.join(', ')
33
+ end
25
34
  end
26
35
 
27
36
  def last_val
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yesql'
4
+ require 'yesql/common/adapter'
5
+
6
+ module ::YeSQL
7
+ module Bindings
8
+ class Transformed
9
+ include ::YeSQL::Common::Adapter
10
+
11
+ def initialize(statement_binds:)
12
+ @statement_binds = statement_binds
13
+ end
14
+
15
+ def call
16
+ return mysql_rails5_binds if rails5? && mysql?
17
+ return mysql_binds if !rails5? && mysql?
18
+
19
+ pg_binds
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :statement_binds
25
+
26
+ def rails5?
27
+ ::Rails::VERSION::MAJOR == 5
28
+ end
29
+
30
+ def mysql_rails5_binds
31
+ statement_binds
32
+ .map(&:first)
33
+ .flatten(1)
34
+ .each_slice(2)
35
+ .flat_map do |first, last|
36
+ next [first, last].map(&:last) if first.is_a?(Array)
37
+
38
+ last
39
+ end
40
+ end
41
+
42
+ def mysql_binds
43
+ statement_binds
44
+ .map(&:first)
45
+ .flatten
46
+ .each_slice(2)
47
+ .to_a
48
+ end
49
+
50
+ def pg_binds
51
+ statement_binds
52
+ .sort_by { |_, position| position.to_s.tr('$', '').to_i }
53
+ .uniq
54
+ .map(&:first)
55
+ .flatten
56
+ .each_slice(2)
57
+ .to_a
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module ::YeSQL
6
+ module Common
7
+ module Adapter
8
+ extend Forwardable
9
+
10
+ # `adapter` might be a complex object, but
11
+ # for the sake of brevity it's just a string
12
+ def adapter
13
+ ::ActiveRecord::Base.connection.adapter_name
14
+ end
15
+
16
+ def mysql?
17
+ adapter == 'Mysql2'
18
+ end
19
+
20
+ def pg?
21
+ adapter == 'PostgreSQL'
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ::YeSQL
4
+ module Config
5
+ class Configuration
6
+ attr_accessor :path
7
+
8
+ DEFAULT_PATH = 'app/yesql'
9
+
10
+ def initialize
11
+ @path = DEFAULT_PATH
12
+ end
13
+ end
14
+ end
15
+
16
+ class << self
17
+ def config
18
+ @config ||= ::YeSQL::Configuration.new
19
+ end
20
+
21
+ def configure
22
+ yield config if block_given?
23
+ end
24
+
25
+ def reset_config
26
+ tap do |conf|
27
+ conf.configure do |configuration|
28
+ configuration.path = ::YeSQL::Configuration::DEFAULT_PATH
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module YeSQL
3
+ require 'yesql/utils/read'
4
+
5
+ module ::YeSQL
4
6
  module Errors
5
7
  module NoBindingsProvidedError
6
8
  def validate_statement_bindings(binds, file_path)
7
9
  return unless statement_binds(file_path).size.positive?
8
10
 
9
11
  format(MESSAGE, renderable_statement_binds(file_path)).tap do |message|
10
- raise ArgumentError, message unless binds.is_a?(Hash) && !binds.empty?
12
+ raise ::ArgumentError, message unless binds.is_a?(::Hash) && !binds.empty?
11
13
  end
12
14
  end
13
15
 
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yesql'
4
+ require 'forwardable'
5
+
6
+ module ::YeSQL
7
+ module Params
8
+ class Output
9
+ extend Forwardable
10
+
11
+ def initialize(output)
12
+ @output = output.to_s
13
+ end
14
+
15
+ def columns?
16
+ output == 'columns'
17
+ end
18
+
19
+ def rows?
20
+ output == 'rows'
21
+ end
22
+
23
+ def hash?
24
+ output == 'hash'
25
+ end
26
+
27
+ def_delegator(:output, :to_sym)
28
+
29
+ private
30
+
31
+ attr_reader :output
32
+ end
33
+ end
34
+ end
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'yesql'
4
- require 'forwardable'
5
4
  require 'yesql/bindings/utils'
5
+ require 'yesql/common/adapter'
6
+ require 'yesql/bindings/transformed'
7
+ require 'yesql/query/result'
8
+ require 'yesql/query/transform_result'
9
+ require 'yesql/params/output'
6
10
 
7
11
  module YeSQL
8
12
  module Query
9
13
  class Performer
10
- extend Forwardable
11
-
12
14
  include ::YeSQL::Bindings::Utils
13
15
 
14
16
  # rubocop:disable Metrics/ParameterLists
@@ -21,19 +23,18 @@ module YeSQL
21
23
  @bind_statement = bind_statement
22
24
  @cache = cache
23
25
  @cache_key = cache[:key] || file_path
24
- @connection = ActiveRecord::Base.connection
25
26
  @expires_in = cache[:expires_in]
26
27
  @file_path = file_path
27
28
  @named_bindings = bindings.transform_keys(&:to_sym)
28
- @output = output
29
+ @output = ::YeSQL::Params::Output.new(output)
29
30
  @prepare = prepare
30
31
  end
31
32
  # rubocop:enable Metrics/ParameterLists
32
33
 
33
34
  def call
34
- return modified_output if cache.empty?
35
+ return transformed_result if cache.empty?
35
36
 
36
- Rails.cache.fetch(cache_key, expires_in: expires_in) { modified_output }
37
+ Rails.cache.fetch(cache_key, expires_in: expires_in) { transformed_result }
37
38
  end
38
39
 
39
40
  private
@@ -41,7 +42,6 @@ module YeSQL
41
42
  attr_reader :bind_statement,
42
43
  :cache,
43
44
  :cache_key,
44
- :connection,
45
45
  :expires_in,
46
46
  :file_path,
47
47
  :named_bindings,
@@ -49,33 +49,24 @@ module YeSQL
49
49
  :prepare,
50
50
  :rows
51
51
 
52
- def_delegator(:query_result, :columns)
53
- private :columns
54
- def_delegator(:query_result, :rows)
55
- private :rows
56
-
57
- def modified_output
58
- @modified_output ||=
59
- begin
60
- return query_result.public_send(output) if %w[columns rows].include?(output.to_s)
61
-
62
- columns.map(&:to_sym).tap { |cols| break rows.map { |row| cols.zip(row).to_h } }
63
- end
52
+ def transformed_result
53
+ @transformed_result ||=
54
+ ::YeSQL::Query::TransformResult.new(output: output, result: query_result).call
64
55
  end
65
56
 
66
57
  def query_result
67
- @query_result ||= connection.exec_query(bind_statement, file_path, binds, prepare: prepare)
58
+ @query_result ||= ::YeSQL::Query::Result.new(binds: binds,
59
+ bind_statement: bind_statement,
60
+ file_path: file_path,
61
+ prepare: prepare).call
68
62
  end
69
63
 
70
64
  def binds
71
- ::YeSQL::Bindings::Extractor.new(bindings: named_bindings).call.tap do |extractor|
72
- break statement_binds(extractor).sort_by(&:last)
73
- .uniq
74
- .map(&:first)
75
- .flatten
76
- .each_slice(2)
77
- .to_a
78
- end
65
+ ::YeSQL::Bindings::Transformed.new(statement_binds: statement_binds(extractor)).call
66
+ end
67
+
68
+ def extractor
69
+ ::YeSQL::Bindings::Extractor.new(bindings: named_bindings).call
79
70
  end
80
71
  end
81
72
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yesql'
4
+ require 'forwardable'
5
+ require 'yesql/common/adapter'
6
+
7
+ module ::YeSQL
8
+ module Query
9
+ class Result
10
+ extend Forwardable
11
+
12
+ include ::YeSQL::Common::Adapter
13
+
14
+ def initialize(binds: [], bind_statement:, file_path:, prepare:)
15
+ @binds = binds
16
+ @bind_statement = bind_statement
17
+ @connection = ActiveRecord::Base.connection
18
+ @file_path = file_path
19
+ @prepare_option = prepare
20
+ end
21
+
22
+ def call
23
+ return view_result if view?
24
+ return rails5_result if ::Rails::VERSION::MAJOR == 5 && mysql?
25
+
26
+ exec_query(bound, file_path, binds, prepare: prepare_option)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :binds, :bind_statement, :connection, :file_path, :prepare_option
32
+
33
+ def_delegators(:bind_statement, :bound, :to_s, :view?)
34
+ def_delegators(:connection, :exec_query, :raw_connection)
35
+ def_delegators(:raw_connection, :prepare)
36
+
37
+ def view_result
38
+ exec_query(bound)
39
+ end
40
+
41
+ def rails5_result
42
+ prepare(bound).execute(*binds)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yesql'
4
+ require 'yesql/common/adapter'
5
+ require 'forwardable'
6
+
7
+ module ::YeSQL
8
+ module Query
9
+ class TransformResult
10
+ extend Forwardable
11
+
12
+ include ::YeSQL::Common::Adapter
13
+
14
+ def initialize(output:, result:)
15
+ @output = output
16
+ @result = result
17
+ end
18
+
19
+ def call
20
+ if ::Rails::VERSION::MAJOR == 5 && mysql?
21
+ return columns if columns?
22
+ return rows_values if rows?
23
+ return array_of_symbol_hashes if hash?
24
+ end
25
+
26
+ return result.public_send(output.to_sym) if columns? || rows?
27
+
28
+ to_a.map(&:symbolize_keys)
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :output, :result
34
+
35
+ def_delegators(:result, :rows, :to_a)
36
+ def_delegators(:output, :columns?, :hash?, :rows?)
37
+
38
+ def rows_values
39
+ to_a.map { |e| e.respond_to?(:values) ? e.values : e }
40
+ end
41
+
42
+ def array_of_symbol_hashes
43
+ to_a.tap { |rows| break hashed_rows(rows) if ::Rails::VERSION::MAJOR == 5 }
44
+ .map { |e| e.respond_to?(:symbolize_keys) ? e.symbolize_keys : e }
45
+ end
46
+
47
+ def hashed_rows(rows)
48
+ rows.map { |row| columns.zip(row).to_h }
49
+ end
50
+
51
+ def columns
52
+ return result.fields if result.respond_to?(:fields)
53
+
54
+ result.columns
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ require 'yesql/utils/read'
6
+ require 'yesql/bindings/extractor'
7
+ require 'yesql/common/adapter'
8
+
9
+ module ::YeSQL
10
+ class Statement
11
+ extend Forwardable
12
+
13
+ include ::YeSQL::Common::Adapter
14
+
15
+ def initialize(bindings = {}, file_path)
16
+ @bindings = bindings
17
+ @connection = ::ActiveRecord::Base.connection
18
+ @file_path = file_path
19
+ end
20
+
21
+ def bound
22
+ to_s.gsub(::YeSQL::BIND_REGEX) do |match|
23
+ extractor[match[/(\w+)/].to_sym].tap do |extract|
24
+ break quote(extract[:value]) if view?
25
+
26
+ break extract[:bind][:vars]
27
+ end
28
+ end
29
+ end
30
+
31
+ def to_s
32
+ @to_s ||= ::YeSQL::Utils::Read.statement(file_path, readable: true)
33
+ end
34
+
35
+ def view?
36
+ to_s =~ /^create\s.*view\s/i
37
+ end
38
+
39
+ private
40
+
41
+ def_delegator(:connection, :quote)
42
+
43
+ attr_reader :bindings, :connection, :file_path
44
+
45
+ def extractor
46
+ ::YeSQL::Bindings::Extractor.new(bindings: bindings).call
47
+ end
48
+ end
49
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YeSQL
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.7'
5
5
  end
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.bindir = 'exe'
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ['lib']
23
- spec.add_dependency 'dry-configurable', '~> 0.11.6'
24
23
  spec.add_dependency 'rails', '>= 5.0'
24
+ spec.add_development_dependency 'mysql2', '~> 0.5.3'
25
25
  spec.add_development_dependency 'pg', '>= 0.18'
26
26
  spec.add_development_dependency 'pry', '~> 0.13.1'
27
27
  spec.add_development_dependency 'rspec', '~> 3.9.0'
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yesql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastián Palma
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-13 00:00:00.000000000 Z
11
+ date: 2020-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: dry-configurable
14
+ name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.11.6
19
+ version: '5.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.11.6
26
+ version: '5.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rails
28
+ name: mysql2
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '5.0'
34
- type: :runtime
33
+ version: 0.5.3
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '5.0'
40
+ version: 0.5.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pg
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -87,6 +87,8 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
+ - ".gitignore"
91
+ - ".rubocop.yml"
90
92
  - Gemfile
91
93
  - Gemfile.lock
92
94
  - LICENSE.txt
@@ -95,15 +97,21 @@ files:
95
97
  - bin/console
96
98
  - bin/setup
97
99
  - lib/yesql.rb
98
- - lib/yesql/bindings/binder.rb
99
100
  - lib/yesql/bindings/extract.rb
100
101
  - lib/yesql/bindings/extractor.rb
102
+ - lib/yesql/bindings/transformed.rb
101
103
  - lib/yesql/bindings/utils.rb
104
+ - lib/yesql/common/adapter.rb
105
+ - lib/yesql/config/configuration.rb
102
106
  - lib/yesql/errors/cache_expiration_error.rb
103
107
  - lib/yesql/errors/file_path_does_not_exist_error.rb
104
108
  - lib/yesql/errors/no_bindings_provided_error.rb
105
109
  - lib/yesql/errors/output_argument_error.rb
110
+ - lib/yesql/params/output.rb
106
111
  - lib/yesql/query/performer.rb
112
+ - lib/yesql/query/result.rb
113
+ - lib/yesql/query/transform_result.rb
114
+ - lib/yesql/statement.rb
107
115
  - lib/yesql/utils/read.rb
108
116
  - lib/yesql/version.rb
109
117
  - yesql.gemspec
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'yesql/utils/read'
4
- require 'yesql/bindings/extractor'
5
-
6
- module YeSQL
7
- module Bindings
8
- class Binder
9
- def self.bind_statement(file_path, bindings)
10
- ::YeSQL::Bindings::Extractor.new(bindings: bindings).call.tap do |extractor|
11
- break ::YeSQL::Utils::Read.statement(file_path, readable: true)
12
- .gsub(::YeSQL::BIND_REGEX) do |match|
13
- extractor[match[/(\w+)/].to_sym][:bind][:vars]
14
- end
15
- end
16
- end
17
- end
18
- end
19
- end