to_wa 0.2.0 → 0.3.0
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/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
|