pg_exec_array_params 0.1.0 → 0.1.1
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/.rubocop.yml +6 -0
- data/Gemfile +6 -2
- data/README.md +33 -6
- data/lib/pg_exec_array_params.rb +18 -1
- data/lib/pg_exec_array_params/column.rb +32 -0
- data/lib/pg_exec_array_params/error.rb +18 -0
- data/lib/pg_exec_array_params/query.rb +27 -92
- data/lib/pg_exec_array_params/rewriters.rb +6 -0
- data/lib/pg_exec_array_params/rewriters/a_expr.rb +80 -0
- data/lib/pg_exec_array_params/rewriters/node.rb +35 -0
- data/lib/pg_exec_array_params/rewriters/res_target.rb +42 -0
- data/lib/pg_exec_array_params/sql_ref_index.rb +31 -0
- data/lib/pg_exec_array_params/version.rb +1 -1
- data/pg_exec_array_params-0.1.0.gem +0 -0
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fdcb04ffde2b46c124f9165cfb0a383e15583d01ae52c830211e51894c44a78
|
4
|
+
data.tar.gz: 410af6e18d74d9feab49848f1796831ac79aefadfccd40614b40743abbacf727
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7f4877366134724817ff915786446d622657d40c820d2b3f1fb31dd3237862366b840c6c0ab483760ad91918b4c238d41db0c89db3301ac981381b032849867
|
7
|
+
data.tar.gz: ccf1a880c9442b5447cd43a43b262e507503b126d0854e21539ec79927a5fb17c5257f6f5d2995d9ac5cde74e3119c45fc8a9dfd1890d6825c7d368bffb02b97
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
@@ -5,11 +5,15 @@ source 'https://rubygems.org'
|
|
5
5
|
# Specify your gem's dependencies in pg_exec_array_params.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
+
gem 'rails'
|
9
|
+
|
8
10
|
gem 'codecov', require: false
|
11
|
+
gem 'pry-byebug', '~> 3.9'
|
12
|
+
gem 'rake', '~> 12.0'
|
13
|
+
gem 'rspec-github', '~> 2.3'
|
14
|
+
gem 'rspec-its', '~> 1.3'
|
9
15
|
gem 'rubocop', '~> 1.0'
|
10
16
|
gem 'rubocop-rspec', '~> 2.0.0.pre'
|
11
|
-
gem 'rspec-github', '~> 2.3'
|
12
|
-
gem 'pry-byebug', '~> 3.9'
|
13
17
|
gem 'simplecov', '~> 0.19'
|
14
18
|
|
15
19
|
group :benchmark do
|
data/README.md
CHANGED
@@ -1,21 +1,38 @@
|
|
1
1
|
# PgExecArrayParams
|
2
2
|
|
3
3
|

|
4
|
+
[](https://badge.fury.io/rb/pg_exec_array_params)
|
5
|
+
[](undefined)
|
4
6
|
|
5
7
|
Use same parametized query and put `Array<T>` instead of any `T`
|
6
8
|
|
7
9
|
## Example
|
8
10
|
|
9
|
-
|
10
|
-
query = 'select * from t1 where a1 = $1 and a2 = $2 and a3 = $3 and a4 = $4'
|
11
|
-
params = [1, [2, 3], 'foo', ['bar', 'baz']]
|
11
|
+
### Inside `WHERE` part
|
12
12
|
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
13
|
+
```ruby
|
14
|
+
# Instead of:
|
15
|
+
# PG::Connection.exec_params(
|
16
|
+
# 'SELECT * FROM "t1" WHERE "a1" = $1 AND "a3" IN ($4, $5, $6) AND "a2" IN ($2, $3)',
|
17
|
+
# [1, 2, 3, "foo", "bar", "baz"]
|
18
|
+
# )
|
19
|
+
query = 'select * from t1 where a1 = $1 and a3 = $3 and a2 = $2'
|
20
|
+
params = [1, [2, 3], ['foo', 'bar', 'baz']]
|
16
21
|
PgExecArrayParams.exec_array_params(conn, query, params)
|
17
22
|
```
|
18
23
|
|
24
|
+
### Inside `SELECT` part
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
# Instead of:
|
28
|
+
# PG::Connection.exec_params(
|
29
|
+
# 'SELECT ARRAY[$1, $2]'
|
30
|
+
# [1, 2]
|
31
|
+
# )
|
32
|
+
PgExecArrayParams.exec_array_params(conn, 'select $1', [[1, 2]])
|
33
|
+
=> [{"array"=>"{1,2}"}]
|
34
|
+
```
|
35
|
+
|
19
36
|
## Problem
|
20
37
|
|
21
38
|
```ruby
|
@@ -40,6 +57,16 @@ PgExecArrayParams.exec_array_params(conn, 'select * from users where id = $1', [
|
|
40
57
|
=> [{"id" => 1}, {"id" => 2}]
|
41
58
|
```
|
42
59
|
|
60
|
+
## Batteries
|
61
|
+
|
62
|
+
This can also provide more info than plain `pg_query` gem:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
sql = 'with y as (select * from s) select x1, y.y1, z.z as z1 from x join z on z.z = x join y on y.y = x'
|
66
|
+
PgExecArrayParams::Query.new(sql, []).columns.map(&:name)
|
67
|
+
=> ['x1', 'y1', 'z1']
|
68
|
+
```
|
69
|
+
|
43
70
|
## Integration with 'pg' gem
|
44
71
|
|
45
72
|
```ruby
|
data/lib/pg_exec_array_params.rb
CHANGED
@@ -1,10 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'pg_exec_array_params/error'
|
4
|
+
require 'pg_exec_array_params/rewriters'
|
5
|
+
require 'pg_exec_array_params/rewriters/node'
|
6
|
+
require 'pg_exec_array_params/rewriters/res_target'
|
7
|
+
require 'pg_exec_array_params/rewriters/a_expr'
|
8
|
+
require 'pg_exec_array_params/sql_ref_index'
|
9
|
+
require 'pg_exec_array_params/column'
|
3
10
|
require 'pg_exec_array_params/query'
|
4
11
|
require 'pg_exec_array_params/version'
|
5
12
|
|
6
13
|
module PgExecArrayParams
|
7
|
-
|
14
|
+
PARAM_REF = 'ParamRef'
|
15
|
+
REXPR = 'rexpr'
|
16
|
+
NUMBER = 'number'
|
17
|
+
LOCATION = 'location'
|
18
|
+
|
19
|
+
# AExpr['kind']
|
20
|
+
EQ_KIND = 0
|
21
|
+
IN_KIND = 7
|
22
|
+
|
23
|
+
class Optional; end
|
24
|
+
|
8
25
|
module_function
|
9
26
|
|
10
27
|
def exec_array_params(conn, sql, params, *args)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgExecArrayParams
|
4
|
+
class Column
|
5
|
+
attr_reader :table, :column_name, :as_name
|
6
|
+
|
7
|
+
def initialize(table:, column_name:, as_name:)
|
8
|
+
@table = table
|
9
|
+
@column_name = column_name
|
10
|
+
@as_name = as_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
@as_name || @column_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_res_target(res_target)
|
18
|
+
return unless (column_ref = res_target.fetch('val', {})['ColumnRef'])
|
19
|
+
|
20
|
+
idents = column_ref['fields'].map { |field| field.fetch('String', {})['str'] }
|
21
|
+
if idents.size <= 1
|
22
|
+
column_name = idents.first
|
23
|
+
else
|
24
|
+
table, column_name, = idents
|
25
|
+
end
|
26
|
+
|
27
|
+
return unless column_name
|
28
|
+
|
29
|
+
new(table: table, column_name: column_name, as_name: res_target['name'])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgExecArrayParams
|
4
|
+
class Error < StandardError
|
5
|
+
attr_accessor :query, :node
|
6
|
+
|
7
|
+
def initialize(message, query = nil, node = nil)
|
8
|
+
super(message)
|
9
|
+
@msg = message
|
10
|
+
@query = query
|
11
|
+
@node = node
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"#{@msg}\n#{@query}\n#{@node}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -4,16 +4,6 @@ require 'pg_query'
|
|
4
4
|
|
5
5
|
module PgExecArrayParams
|
6
6
|
class Query
|
7
|
-
PARAM_REF = 'ParamRef'
|
8
|
-
REXPR = 'rexpr'
|
9
|
-
A_EXPR = 'A_Expr'
|
10
|
-
KIND = 'kind'
|
11
|
-
LOCATION = 'location'
|
12
|
-
NUMBER = 'number'
|
13
|
-
|
14
|
-
EQ_KIND = 0
|
15
|
-
IN_KIND = 7
|
16
|
-
|
17
7
|
attr_reader :query, :args
|
18
8
|
|
19
9
|
def initialize(query, args = [])
|
@@ -26,109 +16,54 @@ module PgExecArrayParams
|
|
26
16
|
end
|
27
17
|
|
28
18
|
def sql
|
29
|
-
|
30
|
-
|
31
|
-
@sql || (rebuild_query! && @sql)
|
19
|
+
should_rebuild? ? (@sql || (rebuild_query! && @sql)) : query
|
32
20
|
end
|
33
21
|
|
34
22
|
def binds
|
35
|
-
|
23
|
+
should_rebuild? ? (@binds ||= args.flatten(1)) : args
|
24
|
+
end
|
36
25
|
|
37
|
-
|
26
|
+
def columns
|
27
|
+
@columns || (rebuild_query! && @columns)
|
38
28
|
end
|
39
29
|
|
40
30
|
private
|
41
31
|
|
42
32
|
def should_rebuild?
|
43
|
-
args.any?
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
@param_idx = 0
|
48
|
-
@ref_idx = 1
|
49
|
-
@binds = []
|
50
|
-
each_param_ref do |value|
|
51
|
-
# puts({value_before: value}.inspect)
|
52
|
-
|
53
|
-
if args[@param_idx].is_a? Array
|
54
|
-
value[KIND] = IN_KIND
|
55
|
-
value[REXPR] = []
|
56
|
-
args[@param_idx].each do |param|
|
57
|
-
raise Error, "Param: #{param.inspect} not primitive" if param.respond_to?(:each)
|
58
|
-
|
59
|
-
value[REXPR] << { PARAM_REF => { NUMBER => @ref_idx } }
|
60
|
-
@binds << param
|
61
|
-
@ref_idx += 1
|
62
|
-
end
|
63
|
-
else
|
64
|
-
value[REXPR][PARAM_REF][NUMBER] = @ref_idx
|
65
|
-
@ref_idx += 1
|
66
|
-
|
67
|
-
# nested_refs == 1 unwraps, wrap it back
|
68
|
-
value[REXPR] = [value[REXPR]] if value[KIND] == IN_KIND
|
69
|
-
|
70
|
-
@binds << args[@param_idx]
|
71
|
-
end
|
72
|
-
|
73
|
-
@param_idx += 1
|
74
|
-
# puts({value_after_: value}.inspect)
|
33
|
+
args.any? do |param|
|
34
|
+
param.is_a?(Array) && (param.none? do |item|
|
35
|
+
item.respond_to?(:each) && raise(Error, "Param includes not primitive: #{item.inspect}")
|
36
|
+
end)
|
75
37
|
end
|
76
|
-
@sql = tree.deparse
|
77
|
-
# puts({sql: @sql, binds: @binds}.inspect)
|
78
|
-
true
|
79
38
|
end
|
80
39
|
|
81
40
|
def tree
|
82
41
|
@tree ||= PgQuery.parse(query)
|
83
42
|
end
|
84
43
|
|
85
|
-
def
|
44
|
+
def rebuild_query!
|
45
|
+
@columns ||= []
|
86
46
|
tree.send :treewalker!, tree.tree do |_expr, key, value, _location|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
'Cannot splice multiple references, leave the only one:',
|
97
|
-
query,
|
98
|
-
refs_underline(value)
|
99
|
-
].join("\n")
|
100
|
-
raise Error, message
|
101
|
-
end
|
102
|
-
end
|
47
|
+
case key
|
48
|
+
when 'targetList'
|
49
|
+
@columns += value.map do |node|
|
50
|
+
Column.from_res_target(node['ResTarget'])
|
51
|
+
end.compact
|
52
|
+
when 'ResTarget'
|
53
|
+
Rewriters::ResTarget.new(value, ref_idx).process
|
54
|
+
when 'A_Expr'
|
55
|
+
Rewriters::AExpr.new(value, ref_idx).process
|
103
56
|
end
|
104
57
|
end
|
58
|
+
@sql = tree.deparse
|
59
|
+
true
|
60
|
+
rescue Error => e
|
61
|
+
e.query = query
|
62
|
+
raise e
|
105
63
|
end
|
106
64
|
|
107
|
-
def
|
108
|
-
|
109
|
-
"#{'^'.rjust(from, ' ')}#{'-'.rjust(size, '-')}^"
|
110
|
-
end
|
111
|
-
|
112
|
-
def refs_at(value)
|
113
|
-
first_ref = value[REXPR].find { |vexpr| vexpr.key?(PARAM_REF) } [PARAM_REF]
|
114
|
-
last_ref = value[REXPR].reverse.find { |vexpr| vexpr.key?(PARAM_REF) } [PARAM_REF]
|
115
|
-
started = first_ref[LOCATION] + 1
|
116
|
-
ended = last_ref[LOCATION] + last_ref[NUMBER].to_s.size
|
117
|
-
[started, ended - started]
|
118
|
-
end
|
119
|
-
|
120
|
-
# = $1
|
121
|
-
# {"kind"=>0, "name"=>[{"String"=>{"str"=>"="}}],
|
122
|
-
# "lexpr"=>{"ColumnRef"=>{"fields"=>[{"String"=>{"str"=>"companies"}}, {"String"=>{"str"=>"id"}}],
|
123
|
-
# "location"=>1242}},
|
124
|
-
# "rexpr"=>{"ParamRef"=>{"number"=>4, "location"=>1261}}, "location"=>1259}
|
125
|
-
def assign_param_via_eq?(value)
|
126
|
-
(value[KIND] == EQ_KIND) && value[REXPR].is_a?(Hash) && value[REXPR].key?(PARAM_REF)
|
127
|
-
end
|
128
|
-
|
129
|
-
# IN ($1), returns number of nested REFs
|
130
|
-
def assign_param_via_in?(value)
|
131
|
-
(value[KIND] == IN_KIND) && value[REXPR].is_a?(Array) && value[REXPR].count { |vexpr| vexpr.key?(PARAM_REF) }
|
65
|
+
def ref_idx
|
66
|
+
@ref_idx ||= SqlRefIndex.new(args)
|
132
67
|
end
|
133
68
|
end
|
134
69
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgExecArrayParams
|
4
|
+
module Rewriters
|
5
|
+
class AExpr < Node
|
6
|
+
KIND = 'kind'
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def should_rewrite?
|
11
|
+
return true if assign_param_via_eq?
|
12
|
+
|
13
|
+
if (nested_refs = assign_param_via_in?)
|
14
|
+
if nested_refs == 1
|
15
|
+
value[REXPR] = value[REXPR].first
|
16
|
+
return true
|
17
|
+
else
|
18
|
+
suggest_n = value[REXPR].first[PARAM_REF][NUMBER]
|
19
|
+
raise Error.new("Leave only `= $#{suggest_n}` and pass an array", nil, self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def rewrite!
|
26
|
+
# puts({value_before: value}.inspect)
|
27
|
+
old_ref_idx = value[REXPR][PARAM_REF][NUMBER] - 1 # one based
|
28
|
+
unless (new_ref_idx = ref_idx[old_ref_idx])
|
29
|
+
raise Error.new("No parameter for $#{old_ref_idx + 1}", nil, self)
|
30
|
+
end
|
31
|
+
|
32
|
+
if new_ref_idx.is_a?(Array)
|
33
|
+
value[KIND] = IN_KIND
|
34
|
+
value[REXPR] = Range.new(*new_ref_idx).map do |param_ref_idx|
|
35
|
+
{ PARAM_REF => { NUMBER => param_ref_idx } }
|
36
|
+
end
|
37
|
+
else
|
38
|
+
value[REXPR][PARAM_REF][NUMBER] = new_ref_idx
|
39
|
+
# nested_refs == 1 unwraps, wrap it back
|
40
|
+
value[REXPR] = [value[REXPR]] if value[KIND] == IN_KIND
|
41
|
+
end
|
42
|
+
# puts({value_after_: value}.inspect)
|
43
|
+
end
|
44
|
+
|
45
|
+
# = $1
|
46
|
+
# {"kind"=>0, "name"=>[{"String"=>{"str"=>"="}}],
|
47
|
+
# "lexpr"=>{"ColumnRef"=>{"fields"=>[{"String"=>{"str"=>"companies"}}, {"String"=>{"str"=>"id"}}],
|
48
|
+
# "location"=>1242}},
|
49
|
+
# "rexpr"=>{"ParamRef"=>{"number"=>4, "location"=>1261}}, "location"=>1259}
|
50
|
+
def assign_param_via_eq?
|
51
|
+
(value[KIND] == EQ_KIND) && value[REXPR].is_a?(Hash) && value[REXPR].key?(PARAM_REF)
|
52
|
+
end
|
53
|
+
|
54
|
+
# IN ($1), returns number of nested REFs
|
55
|
+
def assign_param_via_in?
|
56
|
+
(value[KIND] == IN_KIND) && value[REXPR].is_a?(Array) && value[REXPR].count { |vexpr| vexpr.key?(PARAM_REF) }
|
57
|
+
end
|
58
|
+
|
59
|
+
def refs_at
|
60
|
+
first_ref = wrap_array(value[REXPR]).find { |vexpr| vexpr.key?(PARAM_REF) }&.fetch(PARAM_REF, {})
|
61
|
+
last_ref = wrap_array(value[REXPR]).reverse.find { |vexpr| vexpr.key?(PARAM_REF) }&.fetch(PARAM_REF, {})
|
62
|
+
return unless (start_ref_loc = first_ref[LOCATION])
|
63
|
+
|
64
|
+
return unless (end_ref_loc = last_ref[LOCATION])
|
65
|
+
|
66
|
+
started = start_ref_loc + 1
|
67
|
+
ended = end_ref_loc + last_ref.fetch(NUMBER, '').to_s.size
|
68
|
+
[started, ended - started]
|
69
|
+
end
|
70
|
+
|
71
|
+
def wrap_array(object)
|
72
|
+
if object.respond_to?(:to_ary)
|
73
|
+
object.to_ary || [object]
|
74
|
+
else
|
75
|
+
[object]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgExecArrayParams
|
4
|
+
module Rewriters
|
5
|
+
class Node
|
6
|
+
attr_reader :value, :ref_idx
|
7
|
+
|
8
|
+
def initialize(value, ref_idx)
|
9
|
+
@value = value
|
10
|
+
@ref_idx = ref_idx
|
11
|
+
end
|
12
|
+
|
13
|
+
def process
|
14
|
+
rewrite! if should_rewrite?
|
15
|
+
end
|
16
|
+
|
17
|
+
# used in exception rendering
|
18
|
+
def to_s
|
19
|
+
return '<unknown node position>' unless (from, size = refs_at)
|
20
|
+
|
21
|
+
"#{'^'.rjust(from, ' ')}#{'-'.rjust(size, '-')}^"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# returns start and end index of value string repr inside query
|
27
|
+
# [from, size]
|
28
|
+
def refs_at; end
|
29
|
+
|
30
|
+
def should_rewrite?; end
|
31
|
+
|
32
|
+
def rewrite!; end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgExecArrayParams
|
4
|
+
module Rewriters
|
5
|
+
class ResTarget < Node
|
6
|
+
VAL = 'val'
|
7
|
+
|
8
|
+
def should_rewrite?
|
9
|
+
plain_selection?
|
10
|
+
end
|
11
|
+
|
12
|
+
def rewrite!
|
13
|
+
# puts({value_before: value}.inspect)
|
14
|
+
old_ref_idx = value[VAL][PARAM_REF][NUMBER] - 1 # one based
|
15
|
+
unless (new_ref_idx = ref_idx[old_ref_idx])
|
16
|
+
raise Error.new("No parameter for $#{old_ref_idx + 1}", nil, self)
|
17
|
+
end
|
18
|
+
|
19
|
+
if new_ref_idx.is_a?(Array)
|
20
|
+
elements = Range.new(*new_ref_idx).map do |param_ref_idx|
|
21
|
+
{ PARAM_REF => { NUMBER => param_ref_idx } }
|
22
|
+
end
|
23
|
+
value[VAL] = { 'A_ArrayExpr' => { 'elements' => elements } }
|
24
|
+
else
|
25
|
+
value[VAL][PARAM_REF][NUMBER] = new_ref_idx
|
26
|
+
end
|
27
|
+
# puts({value_after_: value, 'ref_idx' => ref_idx}.inspect)
|
28
|
+
end
|
29
|
+
|
30
|
+
# handle "select $1"
|
31
|
+
# {"val"=>{"ParamRef"=>{"number"=>1, "location"=>7}}, "location"=>7}
|
32
|
+
# AExpr handles "select $1 + 1"
|
33
|
+
def plain_selection?
|
34
|
+
value.key?(VAL) && value[VAL].is_a?(Hash) && value[VAL].key?(PARAM_REF)
|
35
|
+
end
|
36
|
+
|
37
|
+
def refs_at
|
38
|
+
[value[VAL][PARAM_REF][LOCATION] + 1, value[VAL][PARAM_REF][NUMBER].to_s.size]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgExecArrayParams
|
4
|
+
# Calculates inclusive bounds of each element in a flattened list
|
5
|
+
# Bounds are one-based (as sql ref indexes), single value for non-arrays
|
6
|
+
# [1, [2, 3], 4, [5, 6, 7]] => [1, [2, 3], 4, [5, 7]]
|
7
|
+
class SqlRefIndex
|
8
|
+
attr_reader :array
|
9
|
+
|
10
|
+
def initialize(array)
|
11
|
+
@array = array
|
12
|
+
@extra_items = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
sql_ref_index[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
def sql_ref_index
|
20
|
+
@sql_ref_index ||= array.map.with_index(1) do |item, idx|
|
21
|
+
if item.is_a?(Array)
|
22
|
+
add_extra_items = item.size
|
23
|
+
add_extra_items -= 1 if add_extra_items.positive?
|
24
|
+
[idx + @extra_items, idx + (@extra_items += add_extra_items)]
|
25
|
+
else
|
26
|
+
idx + @extra_items
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_exec_array_params
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vlad Bokov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg_query
|
@@ -69,8 +69,16 @@ files:
|
|
69
69
|
- Rakefile
|
70
70
|
- benchmark.rb
|
71
71
|
- lib/pg_exec_array_params.rb
|
72
|
+
- lib/pg_exec_array_params/column.rb
|
73
|
+
- lib/pg_exec_array_params/error.rb
|
72
74
|
- lib/pg_exec_array_params/query.rb
|
75
|
+
- lib/pg_exec_array_params/rewriters.rb
|
76
|
+
- lib/pg_exec_array_params/rewriters/a_expr.rb
|
77
|
+
- lib/pg_exec_array_params/rewriters/node.rb
|
78
|
+
- lib/pg_exec_array_params/rewriters/res_target.rb
|
79
|
+
- lib/pg_exec_array_params/sql_ref_index.rb
|
73
80
|
- lib/pg_exec_array_params/version.rb
|
81
|
+
- pg_exec_array_params-0.1.0.gem
|
74
82
|
- pg_exec_array_params.gemspec
|
75
83
|
homepage: https://github.com/lunatic-cat/pg_exec_array_params
|
76
84
|
licenses:
|
@@ -93,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
101
|
- !ruby/object:Gem::Version
|
94
102
|
version: '0'
|
95
103
|
requirements: []
|
96
|
-
rubygems_version: 3.
|
104
|
+
rubygems_version: 3.0.8
|
97
105
|
signing_key:
|
98
106
|
specification_version: 4
|
99
107
|
summary: PG::Connection#exec_params with arrays
|