sequel-association-filtering 0.0.2 → 0.0.3

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 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