simple-sql 0.5.7 → 0.5.8

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: 0d0a4a51efce9ee15d5162be03fc204009535caab84adbec768090dc1b33358a
4
- data.tar.gz: 161edc1c790492df3c7fec4a0933826adcd6757d1a267fa119dbe75cab856416
3
+ metadata.gz: 8db783548f20bfc4902ecdc7e94c79f8ae8eceeb99c46c4f65dd9b9d55b6c6ea
4
+ data.tar.gz: 357f8228c7b215b5e17eddb9b8bc935ce0e82c54ccac910876df0c428a4759cd
5
5
  SHA512:
6
- metadata.gz: 67be2270fd3b1e456bc573aca3c6afa25bbb070766edbf11bdf4bece2037fd91f636d12b1861f8899106874e995808e876f5fa13f697dc24508ea66bac7ff8f8
7
- data.tar.gz: f06e19bd48a24dded429f6155442748944ee3f61e0e1e5cfb58248a64fa2f0133781d9bd49a90897271cb759a6f1fe1c86d55b8e88d162cdda96f8f9a90e4420
6
+ metadata.gz: a096a8c2837b8e4d0066e99f637751dcdf08cb649465f6eef051cb5955475211199a07ca0f7e6e8792f7c1ca104655883038d6f682ded67dfc408898ebd4aec7
7
+ data.tar.gz: 188763bbe50ccc364f8a159b56f9c173024e46db5ad314fba0878fcb7dbbb758602c0551d484be9fa3e1e15f7d3036cd211cec048e1cd23489549aa9c3d8fe7c
@@ -1,10 +1,12 @@
1
+ # rubocop:disable Metrics/AbcSize
2
+
1
3
  # This module implements an adapter between the Simple::SQL interface
2
4
  # (i.e. ask, all, first, transaction) and a raw connection.
3
5
  #
4
6
  # This module can be mixed onto objects that implement a raw_connection
5
7
  # method, which must return a Pg::Connection.
6
8
 
7
- module Simple::SQL::ConnectionAdapter
9
+ class Simple::SQL::Connection
8
10
  Logging = ::Simple::SQL::Logging
9
11
 
10
12
  # execute one or more sql statements. This method does not allow to pass in
@@ -33,31 +35,25 @@ module Simple::SQL::ConnectionAdapter
33
35
  def all(sql, *args, into: nil, &block)
34
36
  raise ArgumentError, "all no longer support blocks, use each instead." if block
35
37
 
36
- rows = []
37
- my_pg_source_oid = nil
38
-
39
- each_without_conversion(sql, *args, into: into) do |row, pg_source_oid|
40
- rows << row
41
- my_pg_source_oid = pg_source_oid
42
- end
38
+ rows, pg_source_oid, column_info = each_without_conversion(sql, *args, into: into)
43
39
 
44
- record_set = convert_rows_to_result rows, into: into, pg_source_oid: my_pg_source_oid
40
+ result = convert_rows_to_result rows, into: into, pg_source_oid: pg_source_oid
45
41
 
46
42
  # [TODO] - resolve associations. Note that this is only possible if the type
47
43
  # is not an Array (i.e. into is nil)
48
44
 
49
- if sql.is_a?(::Simple::SQL::Connection::Scope) && sql.paginated?
50
- record_set.send(:set_pagination_info, sql)
51
- end
52
-
53
- record_set
45
+ result.pagination_scope = sql if sql.is_a?(::Simple::SQL::Connection::Scope) && sql.paginated?
46
+ result.column_info = column_info
47
+ result
54
48
  end
55
49
 
56
50
  def each(sql, *args, into: nil)
57
51
  raise ArgumentError, "Missing block" unless block_given?
58
52
 
59
- each_without_conversion sql, *args, into: into do |row, pg_source_oid|
60
- record = convert_row_to_record row, into: into, pg_source_oid: pg_source_oid
53
+ rows, pg_source_oid, _column_info = each_without_conversion sql, *args, into: into
54
+
55
+ rows.each do |row|
56
+ record = convert_rows_to_result([row], into: into, pg_source_oid: pg_source_oid).first
61
57
  yield record
62
58
  end
63
59
 
@@ -134,34 +130,45 @@ module Simple::SQL::ConnectionAdapter
134
130
  end
135
131
  end
136
132
 
133
+ # returns an array of decoded entries, if any
137
134
  def each_without_conversion(sql, *args, into: nil)
138
135
  pg_result = exec_logged(sql, *args)
139
136
 
137
+ column_info = collect_column_info(pg_result)
138
+ rows = []
139
+ pg_source_oid = nil
140
+
140
141
  if pg_result.ntuples > 0 && pg_result.nfields > 0
141
- decoder = Decoder.new(self, pg_result, into: (into ? Hash : nil))
142
+ decoder = Decoder.new(pg_result, into: (into ? Hash : nil), column_info: column_info)
142
143
  pg_source_oid = pg_result.ftable(0)
143
144
 
144
145
  pg_result.each_row do |row|
145
- yield decoder.decode(row), pg_source_oid
146
+ rows << decoder.decode(row)
146
147
  end
147
148
  end
148
149
 
150
+ [rows, pg_source_oid, column_info]
151
+ ensure
149
152
  # optimization: If we wouldn't clear here the GC would do this later.
150
- pg_result.clear unless pg_result.autoclear?
153
+ pg_result.clear if pg_result && !pg_result.autoclear?
151
154
  end
152
155
 
153
- def convert_row_to_record(row, into:, pg_source_oid:)
154
- convert_rows_to_result([row], into: into, pg_source_oid: pg_source_oid).first
156
+ def collect_column_info(pg_result)
157
+ return unless pg_result.nfields > 0
158
+
159
+ (0...pg_result.nfields).map do |idx|
160
+ ftype = pg_result.ftype(idx)
161
+ fmod = pg_result.fmod(idx)
162
+
163
+ {
164
+ name: pg_result.fname(idx).to_sym,
165
+ pg_type_name: type_info.pg_type_name(ftype: ftype, fmod: fmod),
166
+ type_name: type_info.type_name(ftype: ftype, fmod: fmod)
167
+ }
168
+ end
155
169
  end
156
170
 
157
171
  def convert_rows_to_result(rows, into:, pg_source_oid:)
158
172
  Result.build(self, rows, target_type: into, pg_source_oid: pg_source_oid)
159
173
  end
160
-
161
- public
162
-
163
- def resolve_type(ftype, fmod)
164
- @resolved_types ||= {}
165
- @resolved_types[[ftype, fmod]] ||= raw_connection.exec("SELECT format_type($1,$2)", [ftype, fmod]).getvalue(0, 0)
166
- end
167
174
  end
@@ -0,0 +1,66 @@
1
+ # rubocop:disable Style/SymbolLiteral
2
+ # rubocop:disable Layout/AlignHash
3
+ # rubocop:disable Style/HashSyntax
4
+
5
+ # This module implements an adapter between the Simple::SQL interface
6
+ # (i.e. ask, all, first, transaction) and a raw connection.
7
+ #
8
+ # This module can be mixed onto objects that implement a raw_connection
9
+ # method, which must return a Pg::Connection.
10
+
11
+ class Simple::SQL::Connection
12
+ def type_info
13
+ @type_info ||= TypeInfo.new(self)
14
+ end
15
+
16
+ class TypeInfo
17
+ def initialize(connection)
18
+ @connection = connection
19
+ end
20
+
21
+ # returns a Symbol
22
+ def pg_type_name(ftype:, fmod:)
23
+ @pg_type_names ||= {}
24
+ @pg_type_names[[ftype, fmod]] ||= _pg_type_name(ftype, fmod)
25
+ end
26
+
27
+ # returns a Symbol
28
+ def type_name(ftype:, fmod:)
29
+ @type_names ||= {}
30
+ @type_names[[ftype, fmod]] ||= _type_name(ftype, fmod)
31
+ end
32
+
33
+ private
34
+
35
+ TYPE_NAMES = {
36
+ :unknown => :"string",
37
+ :"character varying" => :"string",
38
+ :integer => :"integer",
39
+ :bigint => :"integer",
40
+ :numeric => :"float",
41
+ :"double precision" => :"float",
42
+ :"integer[]" => :"integer[]",
43
+ :"character varying[]" => :"string[]",
44
+ :"text[]" => :"string[]",
45
+ :"timestamp without time zone" => :"time",
46
+ :"timestamp with time zone" => :"time",
47
+ :hstore => :"object",
48
+ :json => :"object",
49
+ :jsonb => :"object",
50
+ :boolean => :"boolean"
51
+ }
52
+
53
+ def _pg_type_name(ftype, fmod)
54
+ @connection.raw_connection.exec("SELECT format_type($1,$2)", [ftype, fmod]).getvalue(0, 0).to_sym
55
+ end
56
+
57
+ def _type_name(ftype, fmod)
58
+ pg_type_name = pg_type_name(ftype: ftype, fmod: fmod)
59
+ TYPE_NAMES[pg_type_name] || _custom_type_name(ftype, fmod, pg_type_name)
60
+ end
61
+
62
+ def _custom_type_name(_ftype, _fmod, pg_type_name)
63
+ "UNKNWON #{pg_type_name.inspect}".to_sym
64
+ end
65
+ end
66
+ end
@@ -4,10 +4,12 @@ end
4
4
  require_relative "connection/raw_connection"
5
5
  require_relative "connection/active_record_connection"
6
6
 
7
+ require_relative "connection/base"
7
8
  require_relative "connection/scope"
8
9
  require_relative "connection/reflection"
9
10
  require_relative "connection/insert"
10
11
  require_relative "connection/duplicate"
12
+ require_relative "connection/type_info"
11
13
 
12
14
  # A Connection object.
13
15
  #
@@ -32,8 +34,6 @@ class Simple::SQL::Connection
32
34
  end
33
35
  end
34
36
 
35
- include Simple::SQL::ConnectionAdapter
36
-
37
37
  extend Forwardable
38
38
  delegate [:wait_for_notify] => :raw_connection
39
39
  end
@@ -38,7 +38,7 @@ module Simple::SQL::Helpers::Decoder
38
38
 
39
39
  # HStore parsing
40
40
  module HStore
41
- module_function
41
+ extend self
42
42
 
43
43
  # thanks to https://github.com/engageis/activerecord-postgres-hstore for regexps!
44
44
 
@@ -67,17 +67,16 @@ module Simple::SQL::Helpers::Decoder
67
67
  end
68
68
 
69
69
  module Simple::SQL::Helpers::Decoder
70
- def self.new(connection, result, into:)
71
- if into == Hash then HashRecord.new(connection, result)
72
- elsif result.nfields == 1 then SingleColumn.new(connection, result)
73
- else MultiColumns.new(connection, result)
70
+ def self.new(result, into:, column_info:)
71
+ if into == Hash then HashRecord.new(column_info)
72
+ elsif result.nfields == 1 then SingleColumn.new(column_info)
73
+ else MultiColumns.new(column_info)
74
74
  end
75
75
  end
76
76
 
77
77
  class SingleColumn
78
- def initialize(connection, result)
79
- typename = connection.resolve_type(result.ftype(0), result.fmod(0))
80
- @field_type = typename.to_sym
78
+ def initialize(column_info)
79
+ @field_type = column_info.first.fetch(:pg_type_name)
81
80
  end
82
81
 
83
82
  def decode(row)
@@ -87,11 +86,10 @@ module Simple::SQL::Helpers::Decoder
87
86
  end
88
87
 
89
88
  class MultiColumns
90
- def initialize(connection, result)
91
- @field_types = 0.upto(result.fields.length - 1).map do |idx|
92
- typename = connection.resolve_type(result.ftype(idx), result.fmod(idx))
93
- typename.to_sym
94
- end
89
+ H = ::Simple::SQL::Helpers
90
+
91
+ def initialize(column_info)
92
+ @field_types = H.pluck(column_info, :pg_type_name)
95
93
  end
96
94
 
97
95
  def decode(row)
@@ -102,9 +100,11 @@ module Simple::SQL::Helpers::Decoder
102
100
  end
103
101
 
104
102
  class HashRecord < MultiColumns
105
- def initialize(connection, result)
106
- super(connection, result)
107
- @field_names = result.fields.map(&:to_sym)
103
+ H = ::Simple::SQL::Helpers
104
+
105
+ def initialize(column_info)
106
+ super(column_info)
107
+ @field_names = H.pluck(column_info, :name)
108
108
  end
109
109
 
110
110
  def decode(row)
@@ -1,10 +1,10 @@
1
- # rubocop:disable Naming/AccessorMethodName
2
1
  # rubocop:disable Style/DoubleNegation
3
2
  # rubocop:disable Style/GuardClause
4
3
 
5
4
  require_relative "helpers"
6
5
 
7
6
  class ::Simple::SQL::Result < Array
7
+ attr_accessor :column_info
8
8
  end
9
9
 
10
10
  require_relative "result/records"
@@ -74,15 +74,13 @@ class ::Simple::SQL::Result < Array
74
74
  !!@pagination_scope
75
75
  end
76
76
 
77
- private
78
-
79
77
  def pagination_scope
80
78
  raise "Only available only for paginated scopes" unless paginated?
81
79
 
82
80
  @pagination_scope
83
81
  end
84
82
 
85
- def set_pagination_info(scope)
83
+ def pagination_scope=(scope)
86
84
  raise ArgumentError, "per must be > 0" unless scope.per > 0
87
85
 
88
86
  @pagination_scope = scope
@@ -1,5 +1,5 @@
1
1
  module Simple
2
2
  module SQL
3
- VERSION = "0.5.7"
3
+ VERSION = "0.5.8"
4
4
  end
5
5
  end
data/lib/simple/sql.rb CHANGED
@@ -8,7 +8,6 @@ require_relative "sql/helpers"
8
8
  require_relative "sql/result"
9
9
  require_relative "sql/config"
10
10
  require_relative "sql/logging"
11
- require_relative "sql/connection_adapter"
12
11
  require_relative "sql/connection"
13
12
 
14
13
  module Simple
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.7
4
+ version: 0.5.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
@@ -202,6 +202,7 @@ files:
202
202
  - lib/simple/sql/config.rb
203
203
  - lib/simple/sql/connection.rb
204
204
  - lib/simple/sql/connection/active_record_connection.rb
205
+ - lib/simple/sql/connection/base.rb
205
206
  - lib/simple/sql/connection/duplicate.rb
206
207
  - lib/simple/sql/connection/insert.rb
207
208
  - lib/simple/sql/connection/raw_connection.rb
@@ -212,7 +213,7 @@ files:
212
213
  - lib/simple/sql/connection/scope/filters.rb
213
214
  - lib/simple/sql/connection/scope/order.rb
214
215
  - lib/simple/sql/connection/scope/pagination.rb
215
- - lib/simple/sql/connection_adapter.rb
216
+ - lib/simple/sql/connection/type_info.rb
216
217
  - lib/simple/sql/formatting.rb
217
218
  - lib/simple/sql/fragment.rb
218
219
  - lib/simple/sql/helpers.rb