arin 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +20 -7
- data/lib/arin/check.rb +64 -8
- data/lib/arin/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2fd1981d6157a72fe95604cb03d0600fc451760d
|
4
|
+
data.tar.gz: 2671fca3c0624c6f2a24f65d21d482a117045d10
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82070bd541eee0ecfe9b353cbea7e7d73db7f6b0cf0645f66ba5fcab83ae15feddd54b496a60820df5147d8a46ed39df42d6b793df68f58adde8979767581d62
|
7
|
+
data.tar.gz: f313027570cc47695e7bac51e9dc20ee45a5322a5c268eab12ac001e33ace7edc32a8b74ec80445276ee97bf0dad04fb493a6b9fd954c975837c256688228173
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@ Arin - ActiveRecord integrity checking tool
|
|
7
7
|
Add this line to your application's Gemfile:
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
gem 'arin'
|
10
|
+
gem 'arin'
|
11
11
|
```
|
12
12
|
|
13
13
|
And then execute:
|
@@ -22,21 +22,21 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
Consider the example: Order belongs to User which doesn't exist anymore.
|
24
24
|
|
25
|
-
In order to find models of certain class which points to non-existant entities we need to pass class
|
25
|
+
In order to find models of certain class which points to non-existant entities we need to pass class constant to constructor:
|
26
26
|
```ruby
|
27
27
|
Arin::Check.new(Order).issues
|
28
28
|
|
29
29
|
# callable object style
|
30
30
|
Arin::Check.(Order)
|
31
31
|
```
|
32
|
-
Multiple classes should be passed as array
|
32
|
+
Multiple classes should be passed as array:
|
33
33
|
```ruby
|
34
34
|
Arin::Check.new([Payment, Order]).issues
|
35
35
|
|
36
36
|
# callable object style
|
37
37
|
Arin::Check.([Payment, Order])
|
38
38
|
```
|
39
|
-
Omit parameters to check all loaded models
|
39
|
+
Omit parameters to check all loaded models:
|
40
40
|
```ruby
|
41
41
|
Rails.application.eager_load!
|
42
42
|
Arin::Check.new.issues
|
@@ -45,9 +45,16 @@ Arin::Check.new.issues
|
|
45
45
|
Arin::Check.()
|
46
46
|
```
|
47
47
|
|
48
|
-
Working with found issues collection which is simple array of `Arin::Issue` instances
|
48
|
+
Working with found issues collection which is simple array of `Arin::Issue` instances:
|
49
49
|
```ruby
|
50
|
-
|
50
|
+
issues = Arin::Check.()
|
51
|
+
|
52
|
+
# getting stats
|
53
|
+
issues.group_by(&:class_name).map{ |k,v| Hash[k, v.size] }
|
54
|
+
=> [{"Order"=>3}, {"Payment"=>2}]
|
55
|
+
|
56
|
+
# getting issue info
|
57
|
+
issue = issues.first
|
51
58
|
=> #<Arin::Issue:0x007f9fe2823af0
|
52
59
|
@class_name="Order",
|
53
60
|
@id=6789,
|
@@ -66,6 +73,7 @@ issue.relation_class
|
|
66
73
|
issue.relation_id
|
67
74
|
=> 4567
|
68
75
|
|
76
|
+
# getting reported object
|
69
77
|
issue.object
|
70
78
|
=> #<Order:0x007f9fdfbd9af8
|
71
79
|
id: 6789,
|
@@ -74,6 +82,10 @@ issue.object
|
|
74
82
|
updated_at: Sun, 20 Jun 2017 20:06:36 UTC +00:00>
|
75
83
|
```
|
76
84
|
|
85
|
+
## TODO
|
86
|
+
|
87
|
+
Add tests
|
88
|
+
|
77
89
|
## Development
|
78
90
|
|
79
91
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -82,7 +94,8 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
82
94
|
|
83
95
|
## Contributing
|
84
96
|
|
85
|
-
|
97
|
+
**The main idea behind Arin development is to stay as small and unopinionated as possible**
|
98
|
+
|
86
99
|
Bug reports and pull requests are welcome on GitHub at https://github.com/fmnoise/arin.
|
87
100
|
|
88
101
|
## License
|
data/lib/arin/check.rb
CHANGED
@@ -33,18 +33,36 @@ module Arin
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def query
|
36
|
-
|
37
|
-
classes.each do |klass|
|
38
|
-
klass.reflect_on_all_associations(:belongs_to).each do |relation|
|
39
|
-
q = relation_query(klass, relation) rescue nil
|
40
|
-
subqueries << q if q && processable?(klass, relation)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
subqueries.join <<-SQL
|
36
|
+
queries.join <<-SQL
|
44
37
|
UNION ALL
|
45
38
|
SQL
|
46
39
|
end
|
47
40
|
|
41
|
+
def queries
|
42
|
+
[].tap do |qs|
|
43
|
+
classes.each do |klass|
|
44
|
+
klass.reflect_on_all_associations(:belongs_to).each do |relation|
|
45
|
+
begin
|
46
|
+
if is_polymorphic?(relation)
|
47
|
+
polymorphics(klass, relation).each do |poly|
|
48
|
+
poly_class = poly.safe_constantize
|
49
|
+
if poly_class
|
50
|
+
qs << polymorphic_relation_query(klass, relation, poly_class)
|
51
|
+
else
|
52
|
+
qs << broken_polymorchic_class_query(klass, relation, poly)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
else
|
56
|
+
qs << relation_query(klass, relation) if processable?(klass, relation)
|
57
|
+
end
|
58
|
+
rescue StandardError => e
|
59
|
+
handle_query_failure(klass, relation, e)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
48
66
|
def processable?(klass, relation)
|
49
67
|
klass.table_exists? &&
|
50
68
|
klass.primary_key &&
|
@@ -64,5 +82,43 @@ module Arin
|
|
64
82
|
AND t.#{relation.foreign_key} IS NOT NULL
|
65
83
|
SQL
|
66
84
|
end
|
85
|
+
|
86
|
+
def polymorphic_relation_query(klass, relation, relation_class)
|
87
|
+
<<-SQL
|
88
|
+
SELECT "#{klass.name}" AS class_name,
|
89
|
+
t.#{klass.primary_key} AS id,
|
90
|
+
"#{relation_class}" AS relation_class,
|
91
|
+
t.#{relation.foreign_key} AS relation_id
|
92
|
+
FROM #{klass.table_name} AS t
|
93
|
+
LEFT JOIN #{relation_class.table_name} AS r
|
94
|
+
ON t.#{relation.foreign_key} = r.#{relation_class.primary_key}
|
95
|
+
AND t.#{relation.foreign_type} = "#{relation_class}"
|
96
|
+
WHERE r.#{relation_class.primary_key} IS NULL
|
97
|
+
AND t.#{relation.foreign_key} IS NOT NULL
|
98
|
+
SQL
|
99
|
+
end
|
100
|
+
|
101
|
+
def broken_polymorphic_class_query(klass, relation, relation_class)
|
102
|
+
<<-SQL
|
103
|
+
SELECT "#{klass.name}" AS class_name,
|
104
|
+
t.#{klass.primary_key} AS id,
|
105
|
+
"#{relation_class}" AS relation_class,
|
106
|
+
t.#{relation.foreign_key} AS relation_id
|
107
|
+
FROM #{klass.table_name} AS t
|
108
|
+
WHERE t.#{relation.foreign_type} = "#{relation_class}"
|
109
|
+
SQL
|
110
|
+
end
|
111
|
+
|
112
|
+
def polymorphics(klass, relation)
|
113
|
+
klass.pluck(relation.foreign_type).uniq.compact
|
114
|
+
end
|
115
|
+
|
116
|
+
def is_polymorphic?(relation)
|
117
|
+
relation.options[:polymorphic]
|
118
|
+
end
|
119
|
+
|
120
|
+
def handle_query_failure(klass, relation, e)
|
121
|
+
warn("Cannot process #{relation.name} relation for #{klass}: #{e.message}")
|
122
|
+
end
|
67
123
|
end
|
68
124
|
end
|
data/lib/arin/version.rb
CHANGED