to_wa 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +46 -3
- data/db/migration.rb +17 -3
- data/db/preparation.rb +1 -0
- data/lib/to_wa.rb +19 -11
- data/lib/to_wa/builder.rb +108 -30
- data/lib/to_wa/configuration.rb +45 -0
- data/lib/to_wa/core.rb +0 -2
- data/lib/to_wa/easy_hash_access.rb +13 -0
- data/lib/to_wa/exceptions.rb +7 -0
- data/lib/to_wa/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64fb0e5b6b7555f477aad99eeedfe5d18d083eda
|
4
|
+
data.tar.gz: a0647318b3e575773c68193c4c747a67280509fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1648c143778d42f291f87aa8b2d56b5f9e8001a9fa564ad6e41422c2d15e4643ef8971398d68571e5234874ce9c817e2f25b2b84aa8ce26c9d01b1a93cabd26
|
7
|
+
data.tar.gz: d02ec68c2568671103d721ce2fb291660b569ea4fde6bd71f11d08d6495e063811543b0a3275b7e4a339bdef57f95f785606163820796373121258d969a995f1
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -7,16 +7,38 @@
|
|
7
7
|
# Installation
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
gem '
|
10
|
+
gem 'to_wa'
|
11
11
|
```
|
12
12
|
|
13
13
|
```console
|
14
14
|
bundle install
|
15
15
|
```
|
16
16
|
|
17
|
+
## Use all columns and operators
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
class TestRecord < ActiveRecord::Base
|
21
|
+
extend ToWa
|
22
|
+
|
23
|
+
permit_all_to_wa_operators!
|
24
|
+
permit_all_to_wa_columns!
|
25
|
+
|
26
|
+
# read section: Use specific table columns as left and right
|
27
|
+
permit_all_to_wa_specified_columns!
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
## Or specify columns and operators
|
32
|
+
|
17
33
|
```ruby
|
18
34
|
class TestRecord < ActiveRecord::Base
|
19
35
|
extend ToWa
|
36
|
+
|
37
|
+
permit_to_wa_columns :a, :b, :x
|
38
|
+
permit_to_wa_operators :eq, :ne
|
39
|
+
|
40
|
+
# read section: Use specific table columns as left and right
|
41
|
+
permit_to_wa_specified_columns foo_records: [:a], bar_records: [:b]
|
20
42
|
end
|
21
43
|
```
|
22
44
|
|
@@ -96,7 +118,6 @@ and|and|
|
|
96
118
|
or|or|
|
97
119
|
not|not|It must receive Array that includes only one data. `{ "not": [{ "name": "ToWa" }] }`
|
98
120
|
|
99
|
-
|
100
121
|
# Usage
|
101
122
|
|
102
123
|
(Ofcourse, `ActiveRecord::Relation` will be provided after `to_wa` without `to_sql`.)
|
@@ -135,6 +156,28 @@ TestRecord.to_wa(
|
|
135
156
|
#=> "SELECT `test_records`.* FROM `test_records` WHERE ((`test_records`.`name` = 'ToWa' OR `test_records`.`name` = 'to_wa') AND `test_records`.`gender` = 'male')"
|
136
157
|
```
|
137
158
|
|
159
|
+
## Use specific table columns as left and right
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
class TestRecord < ActiveRecord::Base
|
163
|
+
extend ToWa
|
164
|
+
has_many :users
|
165
|
+
end
|
166
|
+
|
167
|
+
class User < ActiveRecord::Base
|
168
|
+
end
|
169
|
+
|
170
|
+
TestRecord.left_outer_joins(:users).to_wa(
|
171
|
+
{
|
172
|
+
'>': [
|
173
|
+
{ 'col': ['users', 'left_arm_length'] },
|
174
|
+
{ 'col': ['users', 'right_arm_length'] }
|
175
|
+
]
|
176
|
+
}
|
177
|
+
).to_sql
|
178
|
+
#=> "SELECT `test_records`.* FROM `test_records` LEFT OUTER JOIN `users` ON `users`.`test_record_id` = `test_records`.`id` WHERE (`users`.`left_arm_length` > `users`.`right_arm_length`)"
|
179
|
+
```
|
180
|
+
|
138
181
|
## Working with other query
|
139
182
|
|
140
183
|
```ruby
|
@@ -153,4 +196,4 @@ a.to_sql
|
|
153
196
|
#=> "`test_records`.`name` = 'ToWa'"
|
154
197
|
TestRecord.where(a).to_sql
|
155
198
|
#=> "SELECT `test_records`.* FROM `test_records` WHERE `test_records`.`name` = 'ToWa'"
|
156
|
-
```
|
199
|
+
```
|
data/db/migration.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
class ToWaTestMigration < ActiveRecord::Migration[5.1]
|
2
2
|
class << self
|
3
3
|
def up
|
4
|
+
create_table(:users) do |t|
|
5
|
+
t.integer :left_arm_length
|
6
|
+
t.integer :right_arm_length
|
7
|
+
t.references :test_record
|
8
|
+
end
|
9
|
+
|
4
10
|
create_table(:test_records) do |t|
|
5
11
|
t.string :a
|
6
12
|
t.string :b
|
@@ -8,15 +14,23 @@ class ToWaTestMigration < ActiveRecord::Migration[5.1]
|
|
8
14
|
t.integer :x
|
9
15
|
t.integer :y
|
10
16
|
t.integer :z
|
17
|
+
t.string :denied_column
|
11
18
|
end
|
12
19
|
rescue
|
13
20
|
nil
|
14
21
|
end
|
15
22
|
|
16
23
|
def down
|
17
|
-
|
18
|
-
|
19
|
-
|
24
|
+
begin
|
25
|
+
drop_table(:users)
|
26
|
+
rescue
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
begin
|
30
|
+
drop_table(:test_records)
|
31
|
+
rescue
|
32
|
+
nil
|
33
|
+
end
|
20
34
|
end
|
21
35
|
end
|
22
36
|
end
|
data/db/preparation.rb
CHANGED
data/lib/to_wa.rb
CHANGED
@@ -1,21 +1,29 @@
|
|
1
1
|
require 'to_wa/version'
|
2
|
-
require '
|
2
|
+
require 'to_wa/exceptions'
|
3
|
+
require 'to_wa/configuration'
|
4
|
+
require 'to_wa/easy_hash_access'
|
5
|
+
require 'to_wa/builder'
|
6
|
+
require 'to_wa/core'
|
3
7
|
|
4
8
|
module ToWa
|
5
|
-
|
6
|
-
require 'to_wa/core'
|
9
|
+
include ::ToWa::Configuration
|
7
10
|
|
8
|
-
def to_wa(
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
def to_wa(ex)
|
12
|
+
where(
|
13
|
+
::ToWa::Builder.new(
|
14
|
+
arel_table: arel_table,
|
15
|
+
restricted: true,
|
16
|
+
permitted_columns: permitted_to_wa_columns,
|
17
|
+
permitted_operators: permitted_to_wa_operators,
|
18
|
+
permitted_specified_columns: permitted_to_wa_specified_columns,
|
19
|
+
ex: ex,
|
20
|
+
).execute!,
|
21
|
+
)
|
14
22
|
end
|
15
23
|
end
|
16
24
|
|
17
25
|
module Kernel
|
18
|
-
def ToWa(arel_table,
|
19
|
-
::ToWa::
|
26
|
+
def ToWa(arel_table, ex) # rubocop:disable Naming/MethodName
|
27
|
+
::ToWa::Builder.new(restricted: false, arel_table: arel_table, ex: ex).execute!
|
20
28
|
end
|
21
29
|
end
|
data/lib/to_wa/builder.rb
CHANGED
@@ -1,56 +1,134 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'active_record'
|
2
3
|
|
4
|
+
# rubocop:disable Metrics/ClassLength
|
3
5
|
module ToWa
|
4
|
-
|
6
|
+
class Builder
|
7
|
+
using ::ToWa::EasyHashAccess
|
5
8
|
include ActiveRecord::Sanitization
|
6
9
|
|
7
|
-
|
8
|
-
|
10
|
+
# rubocop:disable Metrics/ParameterLists
|
11
|
+
def initialize(
|
12
|
+
restricted:,
|
13
|
+
ex:,
|
14
|
+
arel_table:,
|
15
|
+
permitted_columns: Set.new,
|
16
|
+
permitted_operators: Set.new,
|
17
|
+
permitted_specified_columns: {}
|
18
|
+
)
|
19
|
+
@restricted = restricted
|
20
|
+
@arel_table = arel_table
|
21
|
+
@initial_ex = ex.is_a?(String) ? JSON.parse(ex) : ex
|
22
|
+
@permitted_columns = permitted_columns
|
23
|
+
@permitted_operators = permitted_operators
|
24
|
+
@permitted_specified_columns = permitted_specified_columns
|
9
25
|
end
|
26
|
+
# rubocop:enable Metrics/ParameterLists
|
10
27
|
|
11
|
-
def
|
12
|
-
|
28
|
+
def self.like(v)
|
29
|
+
sanitize_sql_like(v)
|
30
|
+
end
|
31
|
+
|
32
|
+
def execute!
|
33
|
+
decide(@initial_ex)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def restricted?
|
39
|
+
@restricted
|
40
|
+
end
|
41
|
+
|
42
|
+
def permitted_columns?(v)
|
43
|
+
return true unless restricted?
|
44
|
+
@permitted_columns.include?(v)
|
45
|
+
end
|
46
|
+
|
47
|
+
def permitted_operators?(v)
|
48
|
+
return true unless restricted?
|
49
|
+
@permitted_operators.include?(v)
|
13
50
|
end
|
14
51
|
|
15
|
-
def decide(
|
16
|
-
op =
|
17
|
-
|
52
|
+
def decide(ex)
|
53
|
+
op = detect_op!(ex.k)
|
54
|
+
lr_or_exes = ex.v
|
18
55
|
|
19
56
|
case op
|
20
57
|
when 'not'
|
21
|
-
decide(
|
58
|
+
decide(lr_or_exes.first).not
|
22
59
|
when 'and', 'or'
|
23
|
-
add_logic(
|
60
|
+
add_logic(op, lr_or_exes)
|
61
|
+
when 'between'
|
62
|
+
between_to_gteq_and_lteq(*lr_or_exes)
|
24
63
|
else
|
25
|
-
add_comparison(
|
64
|
+
add_comparison(op, *lr_or_exes)
|
26
65
|
end
|
27
66
|
end
|
28
67
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
when 'matches'
|
35
|
-
"%#{ToWa::Builder.like(value)}%"
|
36
|
-
else
|
37
|
-
value
|
38
|
-
end
|
68
|
+
def detect_op!(op)
|
69
|
+
sop = op.to_s
|
70
|
+
raise ::ToWa::DeniedOperator, sop unless permitted_operators?(sop)
|
71
|
+
::ToWa::Core::OPERATORS[sop]
|
72
|
+
end
|
39
73
|
|
40
|
-
|
74
|
+
def add_comparison(op, left, right)
|
75
|
+
normalize_value(left) { normalize_left_table(left) }.send(op, normalize_right(op, right))
|
41
76
|
end
|
42
77
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
78
|
+
def between_to_gteq_and_lteq(left, right)
|
79
|
+
decide({
|
80
|
+
'and' => [
|
81
|
+
{ '>=' => [left, right.first] },
|
82
|
+
{ '<=' => [left, right.second] },
|
83
|
+
],
|
84
|
+
})
|
85
|
+
end
|
48
86
|
|
49
|
-
|
87
|
+
def normalize_left_table(left)
|
88
|
+
raise ::ToWa::DeniedColumn, left unless permitted_columns?(left)
|
89
|
+
@arel_table[left]
|
50
90
|
end
|
51
91
|
|
52
|
-
def
|
53
|
-
|
92
|
+
def normalize_value(o, &block)
|
93
|
+
case
|
94
|
+
when o.is_a?(Hash) && o.k.to_s == 'col'
|
95
|
+
specify_columns(*o.v.map(&:to_s))
|
96
|
+
when block_given?
|
97
|
+
block&.call
|
98
|
+
else
|
99
|
+
o
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def all_specified_columns_allowed?
|
104
|
+
@permitted_specified_columns == ::ToWa::AllSpecifiedColumnsAllowance
|
105
|
+
end
|
106
|
+
|
107
|
+
def permitted_specified_columns?(table, column)
|
108
|
+
return true unless restricted?
|
109
|
+
return true if all_specified_columns_allowed?
|
110
|
+
|
111
|
+
@permitted_specified_columns[table]&.include?(column)
|
112
|
+
end
|
113
|
+
|
114
|
+
def specify_columns(table, column)
|
115
|
+
raise ::ToWa::DeniedColumn, [table, column] unless permitted_specified_columns?(table, column)
|
116
|
+
|
117
|
+
Arel::Table.new(table)[column]
|
118
|
+
end
|
119
|
+
|
120
|
+
def normalize_right(op, right)
|
121
|
+
if op == 'matches'
|
122
|
+
"%#{ToWa::Builder.like(right)}%"
|
123
|
+
else
|
124
|
+
normalize_value(right)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_logic(op, exes)
|
129
|
+
logic = exes[1..-1].inject(decide(exes.first)) { |a, ex| a.send(op, decide(ex)) }
|
130
|
+
Arel::Nodes::Grouping.new(logic)
|
54
131
|
end
|
55
132
|
end
|
56
133
|
end
|
134
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module ToWa
|
4
|
+
module Configuration
|
5
|
+
def permit_to_wa_columns(*columns)
|
6
|
+
@permitted_to_wa_columns = Set.new(columns.map(&:to_s))
|
7
|
+
end
|
8
|
+
|
9
|
+
def permit_all_to_wa_columns!
|
10
|
+
@permitted_to_wa_columns = Set.new(self.column_names)
|
11
|
+
end
|
12
|
+
|
13
|
+
def permit_to_wa_specified_columns(hash)
|
14
|
+
@permitted_to_wa_specified_columns =
|
15
|
+
JSON.parse(hash.to_json).inject({}) { |a, (k, v)| a.merge!(k => Set.new(Array(v))) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def permit_all_to_wa_specified_columns!
|
19
|
+
@permitted_to_wa_specified_columns = ::ToWa::AllSpecifiedColumnsAllowance
|
20
|
+
end
|
21
|
+
|
22
|
+
def permit_to_wa_operators(*operators)
|
23
|
+
@permitted_to_wa_operators = Set.new(operators.map(&:to_s))
|
24
|
+
end
|
25
|
+
|
26
|
+
def permit_all_to_wa_operators!
|
27
|
+
@permitted_to_wa_operators = ToWa::Core::OPERATORS
|
28
|
+
end
|
29
|
+
|
30
|
+
def permitted_to_wa_columns
|
31
|
+
@permitted_to_wa_columns ||= Set.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def permitted_to_wa_specified_columns
|
35
|
+
@permitted_to_wa_specified_columns ||= {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def permitted_to_wa_operators
|
39
|
+
@permitted_to_wa_operators ||= Set.new
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module AllSpecifiedColumnsAllowance
|
44
|
+
end
|
45
|
+
end
|
data/lib/to_wa/core.rb
CHANGED
data/lib/to_wa/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: to_wa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mmmpa
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-01-
|
11
|
+
date: 2018-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -131,7 +131,10 @@ files:
|
|
131
131
|
- db/preparation.rb
|
132
132
|
- lib/to_wa.rb
|
133
133
|
- lib/to_wa/builder.rb
|
134
|
+
- lib/to_wa/configuration.rb
|
134
135
|
- lib/to_wa/core.rb
|
136
|
+
- lib/to_wa/easy_hash_access.rb
|
137
|
+
- lib/to_wa/exceptions.rb
|
135
138
|
- lib/to_wa/version.rb
|
136
139
|
- to_wa.gemspec
|
137
140
|
homepage: http://mmmpa.net
|