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: ff146b722b3e38c2309610aad40275960ac257b8cae86047fb25aa15b1c08e38
4
- data.tar.gz: fd4d3faeef0debbcaabebc11418c5d4543ef17e46c709ca4e332d53eceab0790
3
+ metadata.gz: 6b96fa93edf655b190d3d510e871ab7666218719f0c07e8c5034d47cab3b47c0
4
+ data.tar.gz: 65f1b9fc8f9ed8d0c9fd499eb5bb32477857bd1c4fb9ad0b1e7185ba44fb0a51
5
5
  SHA512:
6
- metadata.gz: c13509e8f28653f671101d17c861c4a03ff118c3f44233fb6a522423b5f7698535a56e712bacd4b22a250d82404cad96086caa5138089ac53bdfecd301257122
7
- data.tar.gz: 4cc33a23a642c60143869391e8ca678d6cb6b3634695be26e607baa0818b2aa9ac4e6a130c67cb732d72078f0ff59710f55818c92de50509a57c64c9a05b76d6
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(self, :association_filter)
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
- ds = yield(_association_filter_dataset(reflection))
22
- where(ds.exists)
27
+ cond = yield(_association_filter_dataset(reflection)).exists
28
+ invert ? exclude(cond) : where(cond)
23
29
  else
24
- cached_dataset(_association_filter_cache_key(reflection, suffix: :bare)) do
25
- where(_association_filter_dataset(reflection).exists)
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, suffix: nil)
65
- :"_association_filter_#{reflection[:model]}_#{reflection[:name]}_#{suffix}"
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
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  module Plugins
3
3
  module AssociationFiltering
4
- VERSION = '0.0.2'
4
+ VERSION = '0.0.3'
5
5
  end
6
6
  end
7
7
  end
@@ -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
@@ -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
@@ -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.2
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-04-17 00:00:00.000000000 Z
11
+ date: 2018-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler