arin 0.1.1 → 0.1.2
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/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