simple-sql 0.5.7 → 0.5.8

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: 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