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 +4 -4
- data/lib/simple/sql/{connection_adapter.rb → connection/base.rb} +35 -28
- data/lib/simple/sql/connection/type_info.rb +66 -0
- data/lib/simple/sql/connection.rb +2 -2
- data/lib/simple/sql/helpers/decoder.rb +16 -16
- data/lib/simple/sql/result.rb +2 -4
- data/lib/simple/sql/version.rb +1 -1
- data/lib/simple/sql.rb +0 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8db783548f20bfc4902ecdc7e94c79f8ae8eceeb99c46c4f65dd9b9d55b6c6ea
|
4
|
+
data.tar.gz: 357f8228c7b215b5e17eddb9b8bc935ce0e82c54ccac910876df0c428a4759cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
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
|
-
|
51
|
-
|
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
|
60
|
-
|
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(
|
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
|
-
|
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
|
153
|
+
pg_result.clear if pg_result && !pg_result.autoclear?
|
151
154
|
end
|
152
155
|
|
153
|
-
def
|
154
|
-
|
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
|
-
|
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(
|
71
|
-
if into == Hash then HashRecord.new(
|
72
|
-
elsif result.nfields == 1 then SingleColumn.new(
|
73
|
-
else MultiColumns.new(
|
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(
|
79
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
-
|
106
|
-
|
107
|
-
|
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)
|
data/lib/simple/sql/result.rb
CHANGED
@@ -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
|
83
|
+
def pagination_scope=(scope)
|
86
84
|
raise ArgumentError, "per must be > 0" unless scope.per > 0
|
87
85
|
|
88
86
|
@pagination_scope = scope
|
data/lib/simple/sql/version.rb
CHANGED
data/lib/simple/sql.rb
CHANGED
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.
|
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/
|
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
|