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