simple-sql 0.4.28 → 0.4.29

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: 0d15e3cf80cc7d5cf308b674a55712a02878e45d1b25b7771248dc020f930d80
4
- data.tar.gz: 258e8a8f695c80a4b630431371689162607aa08d204aea15333f3ad1687565c7
3
+ metadata.gz: 2f70bf7c7bf33282cf573be0fe9371aab9839a7a2fb6e4b3266827871e667575
4
+ data.tar.gz: 5d857fdc4905fb3e5d40b6f51c1e978b4f92b3d7db30a133266d1c0daa72ce63
5
5
  SHA512:
6
- metadata.gz: ee750f741f4bffce5bba59eb938b9fd4ff21854c1ffa1d3b506814a83659a640de508c77cacaf18ca7124f2c3deb684fd3fad239c3337c808b9cf162a770e85c
7
- data.tar.gz: 4f31769ed4cb0a30b18e2864a224d0c87b772439bd6ca3660a44f427b8d0568633a3104931c523dc26160a314a58d814eba71e87b0b1d98b0dec55420ecfed4c
6
+ metadata.gz: 4626339a32bbad1585a8a50b746a55f939ecaf5f671d8b2511b4261446221c8a0be1ef9d2bcfd6193fef5427b3e0a7544af1c25362edca54c8e298f8bfb9d186
7
+ data.tar.gz: 994ddacac8809d15605e6a336699135d7c40361bdf6d7e9e667d618889e92f444b249cb228bf5e84d411762900c74651167d6c65ee6168b41c527baaca1f6bc0
data/.rubocop.yml CHANGED
@@ -10,7 +10,7 @@ AllCops:
10
10
  - 'Rakefile'
11
11
 
12
12
  Metrics/LineLength:
13
- Max: 120
13
+ Max: 140
14
14
 
15
15
  Metrics/MethodLength:
16
16
  Max: 20
@@ -72,3 +72,7 @@ Style/IfUnlessModifier:
72
72
 
73
73
  Style/PerlBackrefs:
74
74
  Enabled: false
75
+
76
+ Style/TrailingUnderscoreVariable:
77
+ Enabled: false
78
+
@@ -1 +1,3 @@
1
+ # rubocop:disable Naming/FileName
2
+
1
3
  # This file is loaded when running bin/console.
@@ -1,6 +1,7 @@
1
1
  # rubocop:disable Metrics/AbcSize
2
2
  # rubocop:disable Metrics/CyclomaticComplexity
3
3
  # rubocop:disable Metrics/PerceivedComplexity
4
+ # rubocop:disable Layout/AlignHash
4
5
 
5
6
  # private
6
7
  module Simple::SQL::Config
@@ -12,7 +12,7 @@ module Simple::SQL::ConnectionAdapter
12
12
  # arguments - since the pg client does not support this - but it allows to
13
13
  # run multiple sql statements separated by ";"
14
14
  def exec(sql)
15
- Logging.yield_logged sql do
15
+ Logging.with_logged_query sql do
16
16
  raw_connection.exec sql
17
17
  end
18
18
  end
@@ -33,6 +33,7 @@ module Simple::SQL::ConnectionAdapter
33
33
 
34
34
  def all(sql, *args, into: nil, &block)
35
35
  raise ArgumentError, "all no longer support blocks, use each instead." if block
36
+
36
37
  rows = []
37
38
  my_pg_source_oid = nil
38
39
 
@@ -67,6 +68,7 @@ module Simple::SQL::ConnectionAdapter
67
68
  # Runs a query and prints the results via "table_print"
68
69
  def print(sql, *args, into: nil)
69
70
  raise ArgumentError, "You cannot call Simple::SQL.print with into: #{into.inspect}" unless into.nil?
71
+
70
72
  require "table_print"
71
73
  records = all sql, *args, into: Hash
72
74
  tp records
@@ -117,7 +119,7 @@ module Simple::SQL::ConnectionAdapter
117
119
  sql = sql_or_scope
118
120
  end
119
121
 
120
- Logging.yield_logged sql, *args do
122
+ Logging.with_logged_query sql, *args do
121
123
  raw_connection.exec_params(sql, Encoder.encode_args(raw_connection, args))
122
124
  end
123
125
  end
@@ -55,6 +55,7 @@ module Simple
55
55
  unless value.is_a?(Fragment)
56
56
  raise ArgumentError, "Pass in override values via SQL.fragment (for #{value.inspect})"
57
57
  end
58
+
58
59
  hsh.update key.to_s => value.to_sql
59
60
  end
60
61
  end
@@ -0,0 +1,60 @@
1
+ module Simple
2
+ module SQL
3
+ module Formatting
4
+ extend self
5
+
6
+ def format(sql, *args)
7
+ sql = format_sql(sql)
8
+
9
+ return sql if args.empty?
10
+
11
+ args = args.map(&:inspect).join(", ")
12
+ sql += " w/args: #{args}"
13
+ sql = sql[0, 98] + "..." if sql.length > 100
14
+ sql
15
+ end
16
+
17
+ def pretty_format(sql, *args)
18
+ sql = if use_pg_format?
19
+ pg_format_sql(sql)
20
+ else
21
+ format_sql(sql)
22
+ end
23
+
24
+ args = args.map(&:inspect).join(", ")
25
+ "#{sql} w/args: #{args}"
26
+ end
27
+
28
+ private
29
+
30
+ def format_sql(sql)
31
+ sql.gsub(/\s*\n\s*/, " ").gsub(/(\A\s+)|(\s+\z)/, "")
32
+ end
33
+
34
+ require "open3"
35
+
36
+ def use_pg_format?
37
+ return @use_pg_format unless @use_pg_format.nil?
38
+
39
+ `which pg_format`
40
+ if $?.exitstatus == 0
41
+ @use_pg_format = true
42
+ else
43
+ Simple::SQL.logger.warn "[sql] simple-sql can use pg_format for logging queries. Please see https://github.com/darold/pgFormatter"
44
+ @use_pg_format = false
45
+ end
46
+ end
47
+
48
+ PG_FORMAT_ARGS = "--function-case 2 --maxlength 15000 --nocomment --spaces 2 --keyword-case 2 --no-comma-end"
49
+
50
+ def pg_format_sql(sql)
51
+ stdin, stdout, _ = Open3.popen2("pg_format #{PG_FORMAT_ARGS} -")
52
+ stdin.print sql
53
+ stdin.close
54
+ formatted = stdout.read
55
+ stdout.close
56
+ formatted
57
+ end
58
+ end
59
+ end
60
+ end
@@ -6,6 +6,7 @@ module Simple::SQL::Helpers::Decoder
6
6
 
7
7
  # rubocop:disable Metrics/AbcSize
8
8
  # rubocop:disable Metrics/CyclomaticComplexity
9
+ # rubocop:disable Naming/UncommunicativeMethodParamName
9
10
  def decode_value(type, s)
10
11
  case type
11
12
  when :unknown then s
@@ -31,7 +32,6 @@ module Simple::SQL::Helpers::Decoder
31
32
  end
32
33
  # rubocop:enable Metrics/AbcSize
33
34
  # rubocop:enable Metrics/CyclomaticComplexity
34
- # rubocop:enable Metrics/MethodLength
35
35
 
36
36
  require "pg_array_parser"
37
37
  extend PgArrayParser
@@ -14,6 +14,7 @@ class Simple::SQL::Helpers::Immutable
14
14
  case object
15
15
  when Array
16
16
  raise ArgumentError, "Object nested too deep (or inner loop?)" if max_depth < 0
17
+
17
18
  object.map { |obj| create obj, max_depth - 1 }
18
19
  when Hash
19
20
  new(object)
@@ -65,6 +66,8 @@ end
65
66
 
66
67
  if $PROGRAM_NAME == __FILE__
67
68
 
69
+ # rubocop:disable Metrics/AbcSize
70
+
68
71
  require "test-unit"
69
72
 
70
73
  class Simple::SQL::Helpers::Immutable::TestCase < Test::Unit::TestCase
@@ -146,5 +149,4 @@ if $PROGRAM_NAME == __FILE__
146
149
  end
147
150
  end
148
151
 
149
- # rubocop:enable Style/ClassAndModuleChildren
150
152
  end
@@ -1,5 +1,7 @@
1
1
  # rubocop:disable Metrics/AbcSize
2
2
  # rubocop:disable Metrics/LineLength
3
+ # rubocop:disable Layout/AlignHash
4
+
3
5
  module Simple
4
6
  module SQL
5
7
  #
@@ -1,3 +1,7 @@
1
+ # rubocop:disable Metrics/AbcSize
2
+
3
+ require_relative "formatting"
4
+
1
5
  module Simple
2
6
  module SQL
3
7
  module Logging
@@ -25,7 +29,10 @@ module Simple
25
29
  return logger if logger
26
30
  end
27
31
 
28
- # returns a stderr_logger
32
+ stderr_logger
33
+ end
34
+
35
+ def stderr_logger
29
36
  @stderr_logger ||= begin
30
37
  logger = Logger.new(STDERR)
31
38
  logger.level = Logger::INFO
@@ -38,25 +45,67 @@ module Simple
38
45
  extend Forwardable
39
46
  delegate [:debug, :info, :warn, :error, :fatal] => :logger
40
47
 
41
- def yield_logged(sql, *args, &_block)
48
+ def slow_query_treshold
49
+ @slow_query_treshold
50
+ end
51
+
52
+ def slow_query_treshold=(slow_query_treshold)
53
+ expect! slow_query_treshold > 0
54
+ @slow_query_treshold = slow_query_treshold
55
+ end
56
+
57
+ def with_logged_query(sql, *args, &_block)
42
58
  r0 = Time.now
43
59
  rv = yield
44
- realtime = Time.now - r0
45
- debug "[sql] %.3f secs: %s" % [realtime, format_query(sql, *args)]
60
+ runtime = Time.now - r0
61
+
62
+ logger.debug do
63
+ "[sql] %.3f secs: %s" % [runtime, Formatting.format(sql, *args)]
64
+ end
65
+
66
+ if slow_query_treshold && runtime > slow_query_treshold
67
+ log_slow_query(sql, *args, runtime: runtime)
68
+ end
69
+
46
70
  rv
47
71
  rescue StandardError => e
48
- realtime = Time.now - r0
49
- warn "[sql] %.3f secs: %s:\n\tfailed with error %s" % [realtime, format_query(sql, *args), e.message]
72
+ runtime = Time.now - r0
73
+ logger.warn do
74
+ "[sql] %.3f secs: %s:\n\tfailed with error %s" % [runtime, Formatting.format(sql, *args), e.message]
75
+ end
76
+
50
77
  raise
51
78
  end
52
79
 
53
80
  private
54
81
 
55
- def format_query(sql, *args)
56
- sql = sql.gsub(/\s*\n\s*/, " ").gsub(/(\A\s+)|(\s+\z)/, "")
57
- return sql if args.empty?
58
- args = args.map(&:inspect).join(", ")
59
- sql + " w/args: #{args}"
82
+ Formatting = ::Simple::SQL::Formatting
83
+
84
+ def log_slow_query(sql, *args, runtime:)
85
+ # Do not try to analyze an EXPLAIN query. This prevents endless recursion here
86
+ # (and, in general, would not be useful anyways.)
87
+ return if sql =~ /^EXPLAIN /
88
+
89
+ log_multiple_lines ::Logger::WARN, prefix: "[sql-slow]" do
90
+ formatted_query = Formatting.pretty_format(sql, *args)
91
+ query_plan = ::Simple::SQL.all "EXPLAIN ANALYZE #{sql}", *args
92
+
93
+ <<~MSG
94
+ === slow query detected: (#{'%.3f secs' % runtime}) ===================================================================================
95
+ #{formatted_query}
96
+ --- query plan: -------------------------------------------------------------------
97
+ #{query_plan.join("\n")}
98
+ ===================================================================================
99
+ MSG
100
+ end
101
+ end
102
+
103
+ def log_multiple_lines(level, str = nil, prefix:)
104
+ logger.log(level) do
105
+ str = yield if str.nil?
106
+ str = str.gsub("\n", "\n#{prefix} ") if prefix
107
+ str
108
+ end
60
109
  end
61
110
  end
62
111
  end
@@ -41,7 +41,7 @@ module Simple
41
41
  SELECT table_schema || '.' || table_name AS name, *
42
42
  FROM information_schema.tables
43
43
  WHERE table_schema=$1
44
- SQL
44
+ SQL
45
45
  records_by_attr(recs, :name)
46
46
  end
47
47
 
@@ -2,6 +2,7 @@
2
2
  # rubocop:disable Metrics/MethodLength
3
3
  # rubocop:disable Metrics/ParameterLists
4
4
  # rubocop:disable Style/GuardClause
5
+ # rubocop:disable Naming/UncommunicativeMethodParamName
5
6
 
6
7
  require "active_support/core_ext/string/inflections"
7
8
 
@@ -164,6 +165,7 @@ module ::Simple::SQL::Result::AssociationLoader # :nodoc:
164
165
  if order_by || limit
165
166
  raise ArgumentError, "#{association.inspect} is a singular association, w/o support for order_by: and limit:"
166
167
  end
168
+
167
169
  preload_belongs_to records, relation, as: as
168
170
  else
169
171
  preload_has_one_or_many records, relation, as: as, order_by: order_by, limit: limit
@@ -1,4 +1,4 @@
1
- # xrubocop:disable Metrics/ParameterLists
1
+ # rubocop:disable Naming/UncommunicativeMethodParamName
2
2
 
3
3
  require_relative "association_loader"
4
4
  require "simple/sql/reflection"
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  class Simple::SQL::Scope
4
2
  def order_by(sql_fragment)
5
3
  duplicate.send(:order_by!, sql_fragment)
@@ -1,5 +1,5 @@
1
1
  module Simple
2
2
  module SQL
3
- VERSION = "0.4.28"
3
+ VERSION = "0.4.29"
4
4
  end
5
5
  end
data/simple-sql.gemspec CHANGED
@@ -38,7 +38,7 @@ Gem::Specification.new do |gem|
38
38
  gem.add_development_dependency 'pg', '0.20'
39
39
  gem.add_development_dependency 'rake', '~> 11'
40
40
  gem.add_development_dependency 'rspec', '~> 3.7'
41
- gem.add_development_dependency 'rubocop', '~> 0.52.1'
41
+ gem.add_development_dependency 'rubocop', '~> 0.61.1'
42
42
  gem.add_development_dependency 'database_cleaner', '~> 1'
43
43
  gem.add_development_dependency 'simplecov', '~> 0'
44
44
  gem.add_development_dependency 'awesome_print', '~> 0'
data/vendor/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pgFormatter-3.1
data/vendor/Makefile ADDED
@@ -0,0 +1,4 @@
1
+ pgFormatter-3.1:
2
+ curl -L -O https://github.com/darold/pgFormatter/archive/v3.1.tar.gz
3
+ tar xvfz v3.1.tar.gz
4
+ cd pgFormatter-3.1 && perl Makefile.PL && make && sudo make install
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.4.28
4
+ version: 0.4.29
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: 2018-12-21 00:00:00.000000000 Z
12
+ date: 2018-12-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pg_array_parser
@@ -115,14 +115,14 @@ dependencies:
115
115
  requirements:
116
116
  - - "~>"
117
117
  - !ruby/object:Gem::Version
118
- version: 0.52.1
118
+ version: 0.61.1
119
119
  type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
123
  - - "~>"
124
124
  - !ruby/object:Gem::Version
125
- version: 0.52.1
125
+ version: 0.61.1
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: database_cleaner
128
128
  requirement: !ruby/object:Gem::Requirement
@@ -203,6 +203,7 @@ files:
203
203
  - lib/simple/sql/connection.rb
204
204
  - lib/simple/sql/connection_adapter.rb
205
205
  - lib/simple/sql/duplicate.rb
206
+ - lib/simple/sql/formatting.rb
206
207
  - lib/simple/sql/helpers.rb
207
208
  - lib/simple/sql/helpers/decoder.rb
208
209
  - lib/simple/sql/helpers/encoder.rb
@@ -245,6 +246,8 @@ files:
245
246
  - spec/support/004_simplecov.rb
246
247
  - spec/support/model/user.rb
247
248
  - tasks/release.rake
249
+ - vendor/.gitignore
250
+ - vendor/Makefile
248
251
  homepage: http://github.com/radiospiel/simple-sql
249
252
  licenses: []
250
253
  metadata: {}