yesql 0.1.6 → 0.2.2

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: 8f432f23ac16148c7439ec096a55c142c9985c537d06ef5ded891fb3178d3bbf
4
- data.tar.gz: b5d82c03933a0401d4b24a3fd48f00ea3864adfb8566db7f73c518714784cc54
3
+ metadata.gz: d4cad8cd91b4afba6c7a8722f9f0dfd6092552d2f4ce735c6880425241122b43
4
+ data.tar.gz: b8be652b46ee03e081ec2d8bc3bcc2321e26e2b7fcd55dcbf2a2bb288ddac139
5
5
  SHA512:
6
- metadata.gz: '084397cf83aa10faf2d724a0be1c11548e36dd515932c4552498c130a96efb044ca5f498aa30d4ec9c002ea1f36c4ec3699bcd4e6e2db2313b0b56fab9da2ae5'
7
- data.tar.gz: 70a91ebc63c23cd5c653351e728fc9c93207fd2583b1b72629d63717ba8e105c86318b016110f3040fd681b176da4d80db2807c40b4859ac3192c1a160901572
6
+ metadata.gz: 4dc794c44484b4fcc8815fa866023c6cf5d2f4b82d4f2c45c6de7e86082eaa3ba838c55e750e3f2fd53b0312b4be699c7ddc900400c8445c377fd7c6d1139190
7
+ data.tar.gz: 88b860a5ce91655366f9d73336b522678a8f709938881e1ff150a13565b57cd12b65c753531ecfb886528d162405c36ca9036c1c3cba52a62aa2e3e3993e76fb
data/.gitignore CHANGED
@@ -2,3 +2,6 @@ spec/minimalpg/log/*
2
2
  spec/minimalmysql/log/*
3
3
  spec/minimalpg/db/*
4
4
  spec/minimalmysql/db/*
5
+
6
+ *.un~
7
+ *.swp
data/.rubocop.yml CHANGED
@@ -1,8 +1,20 @@
1
1
  require: rubocop-rspec
2
2
 
3
+ Metrics/BlockLength:
4
+ Exclude:
5
+ - spec/**/*_spec.rb
6
+ - spec/spec_helper.rb
7
+ - spec/yesql/shared/*
8
+
3
9
  RSpec/FilePath:
4
10
  Exclude:
5
11
  - spec/**/*_spec.rb
6
12
 
7
13
  RSpec/NestedGroups:
8
14
  Enabled: False
15
+
16
+ RSpec/ExampleLength:
17
+ Enabled: False
18
+
19
+ RSpec/BeforeAfterAll:
20
+ Enabled: False
data/Gemfile CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
7
  group :docs do
8
- gem 'yard'
8
+ gem "yard"
9
9
  end
data/Gemfile.lock CHANGED
@@ -1,159 +1,55 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yesql (0.1.5)
5
- rails (>= 5.0)
4
+ yesql (0.2.2)
5
+ activerecord (>= 4.0.0.beta1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- actioncable (6.0.3.4)
11
- actionpack (= 6.0.3.4)
12
- nio4r (~> 2.0)
13
- websocket-driver (>= 0.6.1)
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)
20
- mail (>= 2.7.1)
21
- actionmailer (6.0.3.4)
22
- actionpack (= 6.0.3.4)
23
- actionview (= 6.0.3.4)
24
- activejob (= 6.0.3.4)
25
- mail (~> 2.5, >= 2.5.4)
26
- rails-dom-testing (~> 2.0)
27
- actionpack (6.0.3.4)
28
- actionview (= 6.0.3.4)
29
- activesupport (= 6.0.3.4)
30
- rack (~> 2.0, >= 2.0.8)
31
- rack-test (>= 0.6.3)
32
- rails-dom-testing (~> 2.0)
33
- rails-html-sanitizer (~> 1.0, >= 1.2.0)
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)
39
- nokogiri (>= 1.8.5)
40
- actionview (6.0.3.4)
41
- activesupport (= 6.0.3.4)
42
- builder (~> 3.1)
43
- erubi (~> 1.4)
44
- rails-dom-testing (~> 2.0)
45
- rails-html-sanitizer (~> 1.1, >= 1.2.0)
46
- activejob (6.0.3.4)
47
- activesupport (= 6.0.3.4)
48
- globalid (>= 0.3.6)
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)
58
- marcel (~> 0.3.1)
59
- activesupport (6.0.3.4)
10
+ activemodel (6.1.3.1)
11
+ activesupport (= 6.1.3.1)
12
+ activerecord (6.1.3.1)
13
+ activemodel (= 6.1.3.1)
14
+ activesupport (= 6.1.3.1)
15
+ activesupport (6.1.3.1)
60
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
61
- i18n (>= 0.7, < 2)
62
- minitest (~> 5.1)
63
- tzinfo (~> 1.1)
64
- zeitwerk (~> 2.2, >= 2.2.2)
65
- builder (3.2.4)
17
+ i18n (>= 1.6, < 2)
18
+ minitest (>= 5.1)
19
+ tzinfo (~> 2.0)
20
+ zeitwerk (~> 2.3)
66
21
  coderay (1.1.3)
67
- concurrent-ruby (1.1.7)
68
- crass (1.0.6)
22
+ concurrent-ruby (1.1.8)
69
23
  diff-lcs (1.4.4)
70
- erubi (1.9.0)
71
- globalid (0.4.2)
72
- activesupport (>= 4.2.0)
73
- i18n (1.8.5)
24
+ i18n (1.8.10)
74
25
  concurrent-ruby (~> 1.0)
75
- loofah (2.7.0)
76
- crass (~> 1.0.2)
77
- nokogiri (>= 1.5.9)
78
- mail (2.7.1)
79
- mini_mime (>= 0.1.1)
80
- marcel (0.3.3)
81
- mimemagic (~> 0.3.2)
82
26
  method_source (1.0.0)
83
- mimemagic (0.3.5)
84
- mini_mime (1.0.2)
85
- mini_portile2 (2.4.0)
86
- minitest (5.14.2)
27
+ minitest (5.14.4)
87
28
  mysql2 (0.5.3)
88
- nio4r (2.5.4)
89
- nokogiri (1.10.10)
90
- mini_portile2 (~> 2.4.0)
91
29
  pg (1.2.3)
92
30
  pry (0.13.1)
93
31
  coderay (~> 1.1)
94
32
  method_source (~> 1.0)
95
- rack (2.2.3)
96
- rack-test (1.1.0)
97
- rack (>= 1.0, < 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)
110
- bundler (>= 1.3.0)
111
- railties (= 6.0.3.4)
112
- sprockets-rails (>= 2.0.0)
113
- rails-dom-testing (2.0.3)
114
- activesupport (>= 4.2.0)
115
- nokogiri (>= 1.6)
116
- rails-html-sanitizer (1.3.0)
117
- loofah (~> 2.3)
118
- railties (6.0.3.4)
119
- actionpack (= 6.0.3.4)
120
- activesupport (= 6.0.3.4)
121
- method_source
122
- rake (>= 0.8.7)
123
- thor (>= 0.20.3, < 2.0)
124
- rake (13.0.1)
125
33
  rspec (3.9.0)
126
34
  rspec-core (~> 3.9.0)
127
35
  rspec-expectations (~> 3.9.0)
128
36
  rspec-mocks (~> 3.9.0)
129
- rspec-core (3.9.2)
37
+ rspec-core (3.9.3)
130
38
  rspec-support (~> 3.9.3)
131
- rspec-expectations (3.9.2)
39
+ rspec-expectations (3.9.4)
132
40
  diff-lcs (>= 1.2.0, < 2.0)
133
41
  rspec-support (~> 3.9.0)
134
42
  rspec-mocks (3.9.1)
135
43
  diff-lcs (>= 1.2.0, < 2.0)
136
44
  rspec-support (~> 3.9.0)
137
- rspec-support (3.9.3)
138
- sprockets (4.0.2)
45
+ rspec-support (3.9.4)
46
+ tzinfo (2.0.4)
139
47
  concurrent-ruby (~> 1.0)
140
- rack (> 1, < 3)
141
- sprockets-rails (3.2.2)
142
- actionpack (>= 4.0)
143
- activesupport (>= 4.0)
144
- sprockets (>= 3.0.0)
145
- thor (1.0.1)
146
- thread_safe (0.3.6)
147
- tzinfo (1.2.7)
148
- thread_safe (~> 0.1)
149
- websocket-driver (0.7.3)
150
- websocket-extensions (>= 0.1.0)
151
- websocket-extensions (0.1.5)
152
- yard (0.9.25)
153
- zeitwerk (2.4.0)
48
+ yard (0.9.26)
49
+ zeitwerk (2.4.2)
154
50
 
155
51
  PLATFORMS
156
- ruby
52
+ x86_64-linux
157
53
 
158
54
  DEPENDENCIES
159
55
  mysql2 (~> 0.5.3)
@@ -164,4 +60,4 @@ DEPENDENCIES
164
60
  yesql!
165
61
 
166
62
  BUNDLED WITH
167
- 2.1.4
63
+ 2.2.3
data/README.md CHANGED
@@ -120,28 +120,6 @@ ActiveRecord::Base.connection.execute('SELECT * FROM pg_prepared_statements').to
120
120
  ```
121
121
 
122
122
 
123
- #### `cache`
124
-
125
- If you need to cache your query, you can use the `cache` option. `cache` must be a Hash containing __at least__ the `expires_in` key with an `ActiveSupport::Duration` object, e.g:
126
-
127
- ```ruby
128
- YeSQL('users', cache: { key: 'users', expires_in: 1.hour })
129
- ```
130
-
131
- That's enough to cache the result of the query for 1 hour with the cache key "users".
132
-
133
- If no `key` key/value is used, then the cache key is the name of the file containing the SQL code, and
134
-
135
- ```ruby
136
- YeSQL('users', cache: { key: 'users', expires_in: 1.hour })
137
- ```
138
-
139
- is the same as
140
-
141
- ```ruby
142
- YeSQL('users', cache: { expires_in: 1.hour })
143
- ```
144
-
145
123
  ## Configuration
146
124
 
147
125
  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:
@@ -173,6 +151,12 @@ You can check at anytime what's the configuration path by inspecting the ::YeSQL
173
151
 
174
152
  Bug reports and pull requests are welcome on GitHub at https://github.com/sebastian-palma/yesql. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/sebastian-palma/yesql/blob/master/CODE_OF_CONDUCT.md).
175
153
 
154
+ ## TODO
155
+
156
+ - [ ] Allow comments in .sql files.
157
+ - [ ] Improve errors.
158
+ - [ ] Auto convert `x IN (xs)` queries to `(x = x' OR x = x'')`.
159
+
176
160
 
177
161
  ## License
178
162
 
data/Rakefile CHANGED
@@ -1 +1,3 @@
1
1
  # frozen_string_literal: true
2
+
3
+ require "standard/rake"
data/lib/yesql.rb CHANGED
@@ -1,47 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yesql/version'
4
- require 'yesql/config/configuration'
5
- require 'yesql/query/performer'
6
- require 'yesql/errors/cache_expiration_error'
7
- require 'yesql/errors/file_path_does_not_exist_error'
8
- require 'yesql/errors/no_bindings_provided_error'
9
- require 'yesql/errors/output_argument_error'
10
- require 'yesql/bindings/binder'
3
+ require "yesql/statement"
4
+ require "yesql/version"
5
+ require "yesql/config/configuration"
6
+ require "yesql/query/performer"
7
+ require "yesql/errors/file_path_does_not_exist_error"
8
+ require "yesql/errors/no_bindings_provided_error"
9
+ require "yesql/errors/output_argument_error"
11
10
 
12
11
  module YeSQL
13
12
  include ::YeSQL::Config
14
- include ::YeSQL::Errors::CacheExpirationError
15
13
  include ::YeSQL::Errors::FilePathDoesNotExistError
16
14
  include ::YeSQL::Errors::NoBindingsProvidedError
17
15
  include ::YeSQL::Errors::OutputArgumentError
18
16
 
19
- BIND_REGEX = /(?<!:):(\w+)(?=\b)/.freeze
17
+ BIND_REGEX = /(?<!:):(\w+)(?=\b)/
20
18
 
21
- # rubocop:disable Naming/MethodName
22
19
  def YeSQL(file_path, bindings = {}, options = {})
23
20
  output = options[:output] || :rows
24
- cache = options[:cache] || {}
25
21
 
26
- validate(bindings, cache, file_path, output)
27
- execute(bindings, cache, file_path, output, options)
22
+ validate(bindings, file_path, output)
23
+ execute(bindings, file_path, output, options)
28
24
  end
29
- # rubocop:enable Naming/MethodName
30
25
 
31
26
  private
32
27
 
33
- def validate(bindings, cache, file_path, output)
28
+ def validate(bindings, file_path, output)
34
29
  validate_file_path_existence(file_path)
35
30
  validate_statement_bindings(bindings, file_path)
36
31
  validate_output_options(output)
37
- validate_cache_expiration(cache[:expires_in]) unless cache.empty?
38
32
  end
39
33
 
40
- def execute(bindings, cache, file_path, output, options)
34
+ def execute(bindings, file_path, output, options)
41
35
  ::YeSQL::Query::Performer.new(
42
36
  bindings: bindings,
43
- bind_statement: ::YeSQL::Bindings::Binder.bind_statement(file_path, bindings),
44
- cache: cache,
37
+ bind_statement: ::YeSQL::Statement.new(bindings, file_path),
45
38
  file_path: file_path,
46
39
  output: output,
47
40
  prepare: options[:prepare]
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yesql'
3
+ require "yesql"
4
+ require "yesql/common/adapter"
4
5
 
5
6
  module ::YeSQL
6
7
  module Bindings
@@ -8,9 +9,9 @@ module ::YeSQL
8
9
  include ::YeSQL::Common::Adapter
9
10
 
10
11
  def initialize(indexed_bindings, hash, index, value)
11
- @indexed_bindings = indexed_bindings
12
12
  @hash = hash
13
13
  @index = index
14
+ @indexed_bindings = indexed_bindings
14
15
  @value = value
15
16
  end
16
17
 
@@ -22,13 +23,13 @@ module ::YeSQL
22
23
 
23
24
  def bind_vars
24
25
  if mysql?
25
- return '?' unless array?
26
+ return "?" unless array?
26
27
 
27
- Array.new(value.size, '?').join(', ')
28
+ Array.new(value.size, "?").join(", ")
28
29
  elsif pg?
29
30
  return "$#{last_val}" unless array?
30
31
 
31
- value.map.with_index(bind_index) { |_, i| "$#{i}" }.join(', ')
32
+ value.map.with_index(bind_index) { |_, i| "$#{i}" }.join(", ")
32
33
  end
33
34
  end
34
35
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yesql/bindings/extract'
3
+ require "yesql/bindings/extract"
4
4
 
5
5
  module YeSQL
6
6
  module Bindings
@@ -10,7 +10,6 @@ module YeSQL
10
10
  @indexed_bindings = (bindings || {}).to_a
11
11
  end
12
12
 
13
- # rubocop:disable Metrics/MethodLength
14
13
  def call
15
14
  bindings.each_with_object({}).with_index(1) do |((key, value), hash), index|
16
15
  hash[key] =
@@ -28,7 +27,6 @@ module YeSQL
28
27
  end
29
28
  end
30
29
  end
31
- # rubocop:enable Metrics/MethodLength
32
30
 
33
31
  private
34
32
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yesql'
4
- require 'yesql/common/adapter'
3
+ require "yesql"
4
+ require "yesql/common/adapter"
5
5
 
6
6
  module ::YeSQL
7
7
  module Bindings
@@ -24,16 +24,15 @@ module ::YeSQL
24
24
  attr_reader :statement_binds
25
25
 
26
26
  def rails5?
27
- ::Rails::VERSION::MAJOR == 5
27
+ ::ActiveRecord::VERSION::MAJOR == 5
28
28
  end
29
29
 
30
30
  def mysql_rails5_binds
31
31
  statement_binds
32
- .map(&:first)
33
- .flatten(1)
32
+ .flat_map(&:first)
34
33
  .each_slice(2)
35
34
  .flat_map do |first, last|
36
- next [first, last].map(&:last) if first.is_a?(Array)
35
+ next [first, last].compact.map(&:last) if first.is_a?(Array)
37
36
 
38
37
  last
39
38
  end
@@ -49,7 +48,7 @@ module ::YeSQL
49
48
 
50
49
  def pg_binds
51
50
  statement_binds
52
- .sort_by { |_, position| position.to_s.tr('$', '').to_i }
51
+ .sort_by { |_, position| position.to_s.tr("$", "").to_i }
53
52
  .uniq
54
53
  .map(&:first)
55
54
  .flatten
@@ -4,10 +4,11 @@ module YeSQL
4
4
  module Bindings
5
5
  module Utils
6
6
  def statement_binds(extractor)
7
- ::YeSQL::Utils::Read.statement(file_path, readable: true)
8
- .scan(::YeSQL::BIND_REGEX).map do |(bind)|
9
- extractor[bind.to_sym][:bind].values_at(:vals, :vars)
10
- end
7
+ ::YeSQL::Utils::Read
8
+ .statement(file_path, readable: true)
9
+ .scan(::YeSQL::BIND_REGEX).map do |(bind)|
10
+ extractor[bind.to_sym][:bind].values_at(:vals, :vars)
11
+ end
11
12
  end
12
13
  end
13
14
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
3
+ require "forwardable"
4
4
 
5
5
  module ::YeSQL
6
6
  module Common
7
7
  module Adapter
8
- extend Forwardable
8
+ extend ::Forwardable
9
9
 
10
10
  # `adapter` might be a complex object, but
11
11
  # for the sake of brevity it's just a string
@@ -14,11 +14,11 @@ module ::YeSQL
14
14
  end
15
15
 
16
16
  def mysql?
17
- adapter == 'Mysql2'
17
+ adapter == "Mysql2"
18
18
  end
19
19
 
20
20
  def pg?
21
- adapter == 'PostgreSQL'
21
+ adapter == "PostgreSQL"
22
22
  end
23
23
  end
24
24
  end
@@ -3,11 +3,12 @@
3
3
  module ::YeSQL
4
4
  module Config
5
5
  class Configuration
6
- attr_accessor :path
6
+ attr_accessor :connection, :path
7
7
 
8
- DEFAULT_PATH = 'app/yesql'
8
+ DEFAULT_PATH = "app/yesql"
9
9
 
10
10
  def initialize
11
+ @connection = ""
11
12
  @path = DEFAULT_PATH
12
13
  end
13
14
  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
 
@@ -25,7 +27,7 @@ module YeSQL
25
27
 
26
28
  def statement_binds(file_path)
27
29
  ::YeSQL::Utils::Read.statement(file_path)
28
- .scan(::YeSQL::BIND_REGEX).tap do |scanned_binds|
30
+ .scan(::YeSQL::BIND_REGEX).tap do |scanned_binds|
29
31
  break [] if scanned_binds.size.zero?
30
32
 
31
33
  break scanned_binds.sort
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yesql'
4
- require 'forwardable'
3
+ require "yesql"
4
+ require "forwardable"
5
5
 
6
6
  module ::YeSQL
7
7
  module Params
@@ -13,15 +13,15 @@ module ::YeSQL
13
13
  end
14
14
 
15
15
  def columns?
16
- output == 'columns'
16
+ output == "columns"
17
17
  end
18
18
 
19
19
  def rows?
20
- output == 'rows'
20
+ output == "rows"
21
21
  end
22
22
 
23
23
  def hash?
24
- output == 'hash'
24
+ output == "hash"
25
25
  end
26
26
 
27
27
  def_delegator(:output, :to_sym)
@@ -1,58 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yesql'
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'
3
+ require "yesql"
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"
10
10
 
11
11
  module YeSQL
12
12
  module Query
13
13
  class Performer
14
14
  include ::YeSQL::Bindings::Utils
15
15
 
16
- # rubocop:disable Metrics/ParameterLists
17
- def initialize(bind_statement:,
18
- bindings: {},
19
- cache: {},
20
- file_path:,
21
- output: :rows,
22
- prepare: false)
16
+ def initialize(bind_statement:, file_path:, bindings: {}, output: :rows, prepare: false)
23
17
  @bind_statement = bind_statement
24
- @cache = cache
25
- @cache_key = cache[:key] || file_path
26
- @expires_in = cache[:expires_in]
27
18
  @file_path = file_path
28
19
  @named_bindings = bindings.transform_keys(&:to_sym)
29
20
  @output = ::YeSQL::Params::Output.new(output)
30
21
  @prepare = prepare
31
22
  end
32
- # rubocop:enable Metrics/ParameterLists
33
23
 
34
24
  def call
35
- return modified_output if cache.empty?
36
-
37
- Rails.cache.fetch(cache_key, expires_in: expires_in) { modified_output }
25
+ ::YeSQL::Query::TransformResult.new(output: output, result: query_result).call
38
26
  end
39
27
 
40
28
  private
41
29
 
42
- attr_reader :bind_statement,
43
- :cache,
44
- :cache_key,
45
- :expires_in,
46
- :file_path,
47
- :named_bindings,
48
- :output,
49
- :prepare,
50
- :rows
51
-
52
- def modified_output
53
- @modified_output ||=
54
- ::YeSQL::Query::TransformResult.new(output: output, result: query_result).call
55
- end
30
+ attr_reader :bind_statement, :file_path, :named_bindings, :output, :prepare, :rows
56
31
 
57
32
  def query_result
58
33
  @query_result ||= ::YeSQL::Query::Result.new(binds: binds,
@@ -61,13 +36,13 @@ module YeSQL
61
36
  prepare: prepare).call
62
37
  end
63
38
 
64
- def extractor
65
- ::YeSQL::Bindings::Extractor.new(bindings: named_bindings).call
66
- end
67
-
68
39
  def binds
69
40
  ::YeSQL::Bindings::Transformed.new(statement_binds: statement_binds(extractor)).call
70
41
  end
42
+
43
+ def extractor
44
+ ::YeSQL::Bindings::Extractor.new(bindings: named_bindings).call
45
+ end
71
46
  end
72
47
  end
73
48
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yesql'
4
- require 'forwardable'
5
- require 'yesql/common/adapter'
3
+ require "yesql"
4
+ require "forwardable"
5
+ require "yesql/common/adapter"
6
6
 
7
7
  module ::YeSQL
8
8
  module Query
@@ -11,32 +11,36 @@ module ::YeSQL
11
11
 
12
12
  include ::YeSQL::Common::Adapter
13
13
 
14
- def initialize(binds:, bind_statement:, file_path:, prepare:)
14
+ def initialize(bind_statement:, file_path:, prepare:, binds: [])
15
15
  @binds = binds
16
16
  @bind_statement = bind_statement
17
+ @connection = ActiveRecord::Base.connection
17
18
  @file_path = file_path
18
19
  @prepare_option = prepare
19
20
  end
20
21
 
21
22
  def call
22
- return rails5_result if ::Rails::VERSION::MAJOR == 5 && mysql?
23
+ return view_result if view?
24
+ return rails5_result if ::ActiveRecord::VERSION::MAJOR == 5 && mysql?
23
25
 
24
- exec_query(bind_statement, file_path, binds, prepare: prepare_option)
26
+ exec_query(bound, file_path, binds, prepare: prepare_option)
25
27
  end
26
28
 
27
29
  private
28
30
 
29
- attr_reader :binds, :bind_statement, :file_path, :prepare_option
31
+ attr_reader :binds, :bind_statement, :connection, :file_path, :prepare_option
30
32
 
33
+ def_delegators(:bind_statement, :bound, :to_s, :view?)
31
34
  def_delegators(:connection, :exec_query, :raw_connection)
32
35
  def_delegators(:raw_connection, :prepare)
33
36
 
34
- def connection
35
- ActiveRecord::Base.connection
37
+ def view_result
38
+ exec_query(bound)
36
39
  end
37
40
 
41
+ # TODO: recheck this case
38
42
  def rails5_result
39
- prepare(bind_statement).execute(*binds)
43
+ prepare(bound).execute(*binds)
40
44
  end
41
45
  end
42
46
  end
@@ -1,27 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yesql'
4
- require 'forwardable'
3
+ require "yesql"
4
+ require "yesql/common/adapter"
5
+ require "forwardable"
5
6
 
6
7
  module ::YeSQL
7
8
  module Query
8
9
  class TransformResult
9
10
  extend Forwardable
10
11
 
12
+ include ::YeSQL::Common::Adapter
13
+
11
14
  def initialize(output:, result:)
12
15
  @output = output
13
16
  @result = result
14
17
  end
15
18
 
16
19
  def call
17
- if ::Rails::VERSION::MAJOR == 5
20
+ if ::ActiveRecord::VERSION::MAJOR == 5 && mysql?
18
21
  return columns if columns?
19
22
  return rows_values if rows?
23
+ return array_of_symbol_hashes if hash?
20
24
  end
21
25
 
22
26
  return result.public_send(output.to_sym) if columns? || rows?
23
27
 
24
- array_of_symbol_hashes
28
+ to_a.map(&:symbolize_keys)
25
29
  end
26
30
 
27
31
  private
@@ -36,8 +40,9 @@ module ::YeSQL
36
40
  end
37
41
 
38
42
  def array_of_symbol_hashes
39
- to_a.tap { |rows| break hashed_rows(rows) if ::Rails::VERSION::MAJOR == 5 }
40
- .map { |e| e.respond_to?(:symbolize_keys) ? e.symbolize_keys : e }
43
+ to_a
44
+ .tap { |rows| break hashed_rows(rows) if ::ActiveRecord::VERSION::MAJOR == 5 }
45
+ .map { |e| e.respond_to?(:symbolize_keys) ? e.symbolize_keys : e }
41
46
  end
42
47
 
43
48
  def hashed_rows(rows)
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record"
4
+
5
+ require "forwardable"
6
+
7
+ require "yesql/utils/read"
8
+ require "yesql/bindings/extractor"
9
+ require "yesql/common/adapter"
10
+
11
+ module ::YeSQL
12
+ class Statement
13
+ extend ::Forwardable
14
+
15
+ include ::YeSQL::Common::Adapter
16
+ # Give access to the quote method.
17
+ include ::ActiveRecord::ConnectionAdapters::Quoting
18
+
19
+ def initialize(bindings = {}, file_path)
20
+ @bindings = bindings
21
+ @file_path = file_path
22
+ end
23
+
24
+ def bound
25
+ to_s.gsub(::YeSQL::BIND_REGEX) do |match|
26
+ extractor[match[/(\w+)/].to_sym].tap do |extract|
27
+ break quote(extract[:value]) if view?
28
+
29
+ break extract[:bind][:vars]
30
+ end
31
+ end
32
+ end
33
+
34
+ def to_s
35
+ @to_s ||= ::YeSQL::Utils::Read.statement(file_path, readable: true)
36
+ end
37
+
38
+ def view?
39
+ to_s =~ /^create\s.*view\s/i
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :bindings, :file_path
45
+
46
+ def extractor
47
+ ::YeSQL::Bindings::Extractor.new(bindings: bindings).call
48
+ end
49
+ end
50
+ end
@@ -7,7 +7,7 @@ module YeSQL
7
7
  Dir["./#{::YeSQL.config.path}/**/*.sql"]
8
8
  .find { |dir_file_path| dir_file_path.include?("#{file_path}.sql") }
9
9
  .tap do |sql_file_path|
10
- break File.readlines(sql_file_path, chomp: true).join(' ') if readable == true
10
+ break File.readlines(sql_file_path, chomp: true).join(" ") if readable == true
11
11
 
12
12
  break File.read(sql_file_path)
13
13
  end
data/lib/yesql/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YeSQL
4
- VERSION = '0.1.6'
4
+ VERSION = "0.2.2"
5
5
  end
data/yesql.gemspec CHANGED
@@ -1,28 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lib/yesql/version'
3
+ require_relative "lib/yesql/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = 'yesql'
6
+ spec.name = "yesql"
7
7
  spec.version = YeSQL::VERSION
8
- spec.authors = ['Sebastián Palma']
9
- spec.email = ['vnhnhm.github@gmail.com']
10
- spec.summary = 'Ruby library to use SQL'
8
+ spec.authors = ["Sebastián Palma"]
9
+ spec.email = ["vnhnhm.github@gmail.com"]
10
+ spec.summary = "Ruby library to use SQL"
11
11
  spec.description = 'SQL "raw" for Rails projects'
12
- spec.homepage = 'https://github.com/sebastian-palma/yesql'
13
- spec.license = 'MIT'
14
- spec.metadata['homepage_uri'] = spec.homepage
15
- spec.metadata['source_code_uri'] = 'https://github.com/sebastian-palma/yesql'
16
- spec.metadata['changelog_uri'] = 'https://github.com/sebastian-palma/yesql'
12
+ spec.homepage = "https://github.com/sebastian-palma/yesql"
13
+ spec.license = "MIT"
14
+ spec.metadata["homepage_uri"] = spec.homepage
15
+ spec.metadata["source_code_uri"] = "https://github.com/sebastian-palma/yesql"
16
+ spec.metadata["changelog_uri"] = "https://github.com/sebastian-palma/yesql"
17
17
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
18
18
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
19
  end
20
- spec.bindir = 'exe'
20
+ spec.bindir = "exe"
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
- spec.require_paths = ['lib']
23
- spec.add_dependency 'rails', '>= 5.0'
24
- spec.add_development_dependency 'mysql2', '~> 0.5.3'
25
- spec.add_development_dependency 'pg', '>= 0.18'
26
- spec.add_development_dependency 'pry', '~> 0.13.1'
27
- spec.add_development_dependency 'rspec', '~> 3.9.0'
22
+ spec.require_paths = ["lib"]
23
+ spec.add_dependency "activerecord", ">= 4.0.0.beta1"
24
+ spec.add_development_dependency "mysql2", "~> 0.5.3"
25
+ spec.add_development_dependency "pg", ">= 0.18"
26
+ spec.add_development_dependency "pry", "~> 0.13.1"
27
+ spec.add_development_dependency "rspec", "~> 3.9.0"
28
28
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yesql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastián Palma
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-26 00:00:00.000000000 Z
11
+ date: 2021-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: activerecord
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: 4.0.0.beta1
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: '5.0'
26
+ version: 4.0.0.beta1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: mysql2
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -97,14 +97,12 @@ files:
97
97
  - bin/console
98
98
  - bin/setup
99
99
  - lib/yesql.rb
100
- - lib/yesql/bindings/binder.rb
101
100
  - lib/yesql/bindings/extract.rb
102
101
  - lib/yesql/bindings/extractor.rb
103
102
  - lib/yesql/bindings/transformed.rb
104
103
  - lib/yesql/bindings/utils.rb
105
104
  - lib/yesql/common/adapter.rb
106
105
  - lib/yesql/config/configuration.rb
107
- - lib/yesql/errors/cache_expiration_error.rb
108
106
  - lib/yesql/errors/file_path_does_not_exist_error.rb
109
107
  - lib/yesql/errors/no_bindings_provided_error.rb
110
108
  - lib/yesql/errors/output_argument_error.rb
@@ -112,6 +110,7 @@ files:
112
110
  - lib/yesql/query/performer.rb
113
111
  - lib/yesql/query/result.rb
114
112
  - lib/yesql/query/transform_result.rb
113
+ - lib/yesql/statement.rb
115
114
  - lib/yesql/utils/read.rb
116
115
  - lib/yesql/version.rb
117
116
  - yesql.gemspec
@@ -122,7 +121,7 @@ metadata:
122
121
  homepage_uri: https://github.com/sebastian-palma/yesql
123
122
  source_code_uri: https://github.com/sebastian-palma/yesql
124
123
  changelog_uri: https://github.com/sebastian-palma/yesql
125
- post_install_message:
124
+ post_install_message:
126
125
  rdoc_options: []
127
126
  require_paths:
128
127
  - lib
@@ -137,8 +136,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
136
  - !ruby/object:Gem::Version
138
137
  version: '0'
139
138
  requirements: []
140
- rubygems_version: 3.1.2
141
- signing_key:
139
+ rubygems_version: 3.2.3
140
+ signing_key:
142
141
  specification_version: 4
143
142
  summary: Ruby library to use SQL
144
143
  test_files: []
@@ -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
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YeSQL
4
- module Errors
5
- module CacheExpirationError
6
- def validate_cache_expiration(expires_in)
7
- raise ArgumentError, MESSAGE unless expires_in.is_a?(ActiveSupport::Duration)
8
- end
9
-
10
- MESSAGE = <<~MSG
11
- Missing mandatory `expires_in` option for `cache`.
12
-
13
- Can not cache the result of the query without an expiration date.
14
- MSG
15
- private_constant :MESSAGE
16
- end
17
- end
18
- end