sequel-association-filtering 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b96fa93edf655b190d3d510e871ab7666218719f0c07e8c5034d47cab3b47c0
|
4
|
+
data.tar.gz: 65f1b9fc8f9ed8d0c9fd499eb5bb32477857bd1c4fb9ad0b1e7185ba44fb0a51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0642b74414f320c1152478c25cf34694c152b1f15c96204fc1e17929df7b6671e60fe31f46367cedac198df3a59b7fe11cb117602e7937c4f7bf5d8864a179f
|
7
|
+
data.tar.gz: d70a6cc39248e252a46d7d0c14dd31bbbbd5838531267a0a5d1e8c6b7746b039c4e0e4da440aced09b204c02faba98b6185b6ffbcd8bb2f3d11f67e132ca7894
|
@@ -7,30 +7,47 @@ module Sequel
|
|
7
7
|
class Error < StandardError; end
|
8
8
|
|
9
9
|
module ClassMethods
|
10
|
-
Plugins.def_dataset_methods(
|
10
|
+
Plugins.def_dataset_methods(
|
11
|
+
self,
|
12
|
+
[
|
13
|
+
:association_filter,
|
14
|
+
:association_exclude,
|
15
|
+
]
|
16
|
+
)
|
11
17
|
end
|
12
18
|
|
13
19
|
module DatasetMethods
|
14
|
-
def association_filter(association_name)
|
20
|
+
def association_filter(association_name, invert: false)
|
15
21
|
reflection =
|
16
22
|
model.association_reflections.fetch(association_name) do
|
17
23
|
raise Error, "association #{association_name} not found on model #{model}"
|
18
24
|
end
|
19
25
|
|
20
26
|
if block_given?
|
21
|
-
|
22
|
-
where(
|
27
|
+
cond = yield(_association_filter_dataset(reflection)).exists
|
28
|
+
invert ? exclude(cond) : where(cond)
|
23
29
|
else
|
24
|
-
|
25
|
-
|
30
|
+
cache_key =
|
31
|
+
_association_filter_cache_key(
|
32
|
+
reflection: reflection,
|
33
|
+
extra: :"bare_#{invert}",
|
34
|
+
)
|
35
|
+
|
36
|
+
cached_dataset(cache_key) do
|
37
|
+
cond = _association_filter_dataset(reflection).exists
|
38
|
+
invert ? exclude(cond) : where(cond)
|
26
39
|
end
|
27
40
|
end
|
28
41
|
end
|
29
42
|
|
43
|
+
def association_exclude(association_name, &block)
|
44
|
+
association_filter(association_name, invert: true, &block)
|
45
|
+
end
|
46
|
+
|
30
47
|
private
|
31
48
|
|
32
49
|
def _association_filter_dataset(reflection)
|
33
|
-
cache_key = _association_filter_cache_key(reflection)
|
50
|
+
cache_key = _association_filter_cache_key(reflection: reflection)
|
34
51
|
|
35
52
|
ds = reflection.associated_dataset
|
36
53
|
|
@@ -61,8 +78,8 @@ module Sequel
|
|
61
78
|
end
|
62
79
|
end
|
63
80
|
|
64
|
-
def _association_filter_cache_key(reflection
|
65
|
-
:"_association_filter_#{reflection[:model]}_#{reflection[:name]}_#{
|
81
|
+
def _association_filter_cache_key(reflection:, extra: nil)
|
82
|
+
:"_association_filter_#{reflection[:model]}_#{reflection[:name]}_#{extra}"
|
66
83
|
end
|
67
84
|
end
|
68
85
|
end
|
data/spec/many_to_many_spec.rb
CHANGED
@@ -70,4 +70,30 @@ class ManyToManySpec < AssociationFilteringSpecs
|
|
70
70
|
assert_includes record.genres.map(&:id), 5
|
71
71
|
end
|
72
72
|
end
|
73
|
+
|
74
|
+
describe "association_exclude through a many_to_many_association" do
|
75
|
+
it "should support an empty filter that checks for existence" do
|
76
|
+
expected_count = 100 - DB[:album_genres].distinct(:album_id).count
|
77
|
+
|
78
|
+
ds = Album.association_exclude(:genres)
|
79
|
+
assert_equal %(SELECT * FROM "albums" WHERE NOT (EXISTS (SELECT 1 FROM "genres" INNER JOIN "album_genres" ON ("album_genres"."genre_id" = "genres"."id") WHERE ("album_genres"."album_id" = "albums"."id")))), ds.sql
|
80
|
+
assert_equal expected_count, ds.count
|
81
|
+
|
82
|
+
album_id_to_delete = DB[:album_genres].order_by{random.function}.get(:album_id)
|
83
|
+
|
84
|
+
DB[:album_genres].where(album_id: album_id_to_delete).delete
|
85
|
+
assert_equal expected_count + 1, ds.count
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should support a simple filter" do
|
89
|
+
expected_count = 100 - DB[:album_genres].where(genre_id: 5).distinct(:album_id).count
|
90
|
+
|
91
|
+
ds = Album.association_exclude(:genres){|t| t.where(Sequel[:genres][:id] =~ 5)}
|
92
|
+
assert_equal expected_count, ds.count
|
93
|
+
assert_equal %(SELECT * FROM \"albums\" WHERE NOT (EXISTS (SELECT 1 FROM "genres" INNER JOIN "album_genres" ON ("album_genres"."genre_id" = "genres"."id") WHERE (("album_genres"."album_id" = "albums"."id") AND ("genres"."id" = 5))))), ds.sql
|
94
|
+
|
95
|
+
record = ds.first!
|
96
|
+
refute_includes record.genres.map(&:id), 5
|
97
|
+
end
|
98
|
+
end
|
73
99
|
end
|
data/spec/many_to_one_spec.rb
CHANGED
@@ -45,4 +45,15 @@ class ManyToOneSpec < AssociationFilteringSpecs
|
|
45
45
|
assert_includes [5, 10], record.artist_id
|
46
46
|
end
|
47
47
|
end
|
48
|
+
|
49
|
+
describe "association_exclude through a many_to_one association" do
|
50
|
+
it "should support a simple filter" do
|
51
|
+
ds = Album.association_exclude(:artist){|a| a.where{mod(id, 5) =~ 0}}
|
52
|
+
assert_equal 80, ds.count
|
53
|
+
assert_equal %(SELECT * FROM "albums" WHERE NOT (EXISTS (SELECT 1 FROM "artists" WHERE (("artists"."id" = "albums"."artist_id") AND (mod("id", 5) = 0)) LIMIT 1))), ds.sql
|
54
|
+
|
55
|
+
record = ds.order_by{random.function}.first
|
56
|
+
refute_includes [5, 10], record.artist_id
|
57
|
+
end
|
58
|
+
end
|
48
59
|
end
|
data/spec/one_to_many_spec.rb
CHANGED
@@ -129,5 +129,26 @@ class OneToManySpec < AssociationFilteringSpecs
|
|
129
129
|
assert_equal 99, ds.count
|
130
130
|
end
|
131
131
|
end
|
132
|
+
|
133
|
+
describe "association_exclude through a one_to_many association" do
|
134
|
+
it "should support a simple filter" do
|
135
|
+
ds = Artist.association_exclude(:albums){|t| t.where(serial_column: 40)}
|
136
|
+
|
137
|
+
assert_equal 99, ds.count
|
138
|
+
assert_equal %(SELECT * FROM "artists" WHERE NOT (EXISTS (SELECT 1 FROM "albums" WHERE (("albums"."id_1" = "artists"."id_1") AND ("albums"."id_2" = "artists"."id_2") AND ("serial_column" = 40))))), ds.sql
|
139
|
+
|
140
|
+
artists = ds.all
|
141
|
+
refute_includes artists.flat_map(&:albums).map(&:serial_column), 40
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should support an empty filter that checks for existence" do
|
145
|
+
ds = Artist.association_exclude(:albums)
|
146
|
+
assert_equal 0, ds.count
|
147
|
+
assert_equal %(SELECT * FROM "artists" WHERE NOT (EXISTS (SELECT 1 FROM "albums" WHERE (("albums"."id_1" = "artists"."id_1") AND ("albums"."id_2" = "artists"."id_2"))))), ds.sql
|
148
|
+
|
149
|
+
Album.where(id_1: 5, id_2: 6).delete
|
150
|
+
assert_equal 1, ds.count
|
151
|
+
end
|
152
|
+
end
|
132
153
|
end
|
133
154
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel-association-filtering
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Hanks
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|