flipper-active_record 1.2.2 → 1.3.0

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: '058253d0f5339510f6fed06b6386b95df879657bf8e7d09132e527cb249dfcd8'
4
- data.tar.gz: 073655acecd4aeed5261f6eeaac66299f2f7212887afd4b96b0f535da5e01015
3
+ metadata.gz: cd8f5a24abcc3c82a2335e17b796fa84721522eb92bf138ebab4146b58da7fdc
4
+ data.tar.gz: c39a1899083f55078e7ca28e23d8b1363609ca1322be6d4f32cfcd23922440e2
5
5
  SHA512:
6
- metadata.gz: ff1113b757308e8270eaeb3e77b76b626808bddd686e1e12c5f7dbb4640cb970e09f183028ea77c38fd6ab15ca029206884822a3587963ffc9bf4bebbf930184
7
- data.tar.gz: 01f87ae47c2e6dd0bb00895bb302b3c55ed45cd906c62e5bf70ef3a6e322f91ec1f0beee07711f905722d3347ffb5a393dbba7b797f75e90393e558c37940be2
6
+ metadata.gz: 16b65bea23bf718930e3509b47ba4719ba4baf93dd86bccf69b292130a7732eff1ab7ea9843c9d4a7342e8180cafd08513bcdd14997be5189e6923afe575e499
7
+ data.tar.gz: '01816a252d70e1a9c0bd7215893c54f6ac5dd9444cf9c86b571455edb9b45b0b6bae6072a1e678d283eb70c067a738071a7b7625ace489464dda551574a36121'
@@ -6,10 +6,13 @@ require 'benchmark/ips'
6
6
 
7
7
  flipper = Flipper.new(Flipper::Adapters::ActiveRecord.new)
8
8
 
9
- 2000.times do |i|
10
- flipper.enable_actor :foo, Flipper::Actor.new("User;#{i}")
9
+ 10.times do |n|
10
+ 2000.times do |i|
11
+ flipper.enable_actor 'feature' + n.to_s, Flipper::Actor.new("User;#{i}")
12
+ end
11
13
  end
12
14
 
13
15
  Benchmark.ips do |x|
14
16
  x.report("get_all") { flipper.preload_all }
17
+ x.report("features") { flipper.features }
15
18
  end
@@ -21,6 +21,8 @@ module Flipper
21
21
  ].join
22
22
 
23
23
  has_many :gates, foreign_key: "feature_key", primary_key: "key"
24
+
25
+ validates :key, presence: true
24
26
  end
25
27
 
26
28
  # Private: Do not use outside of this adapter.
@@ -30,6 +32,9 @@ module Flipper
30
32
  "flipper_gates",
31
33
  Model.table_name_suffix,
32
34
  ].join
35
+
36
+ validates :feature_key, presence: true
37
+ validates :key, presence: true
33
38
  end
34
39
 
35
40
  VALUE_TO_TEXT_WARNING = <<-EOS
@@ -59,7 +64,7 @@ module Flipper
59
64
 
60
65
  # Public: The set of known features.
61
66
  def features
62
- with_connection(@feature_class) { @feature_class.all.map(&:key).to_set }
67
+ with_connection(@feature_class) { @feature_class.distinct.pluck(:key).to_set }
63
68
  end
64
69
 
65
70
  # Public: Adds a feature to the set of known features.
@@ -68,9 +73,9 @@ module Flipper
68
73
  # race condition, but add is only used by enable/disable which happen
69
74
  # super rarely, so it shouldn't matter in practice
70
75
  @feature_class.transaction do
71
- unless @feature_class.where(key: feature.key).first
76
+ unless @feature_class.where(key: feature.key).exists?
72
77
  begin
73
- @feature_class.create! { |f| f.key = feature.key }
78
+ @feature_class.create!(key: feature.key)
74
79
  rescue ::ActiveRecord::RecordNotUnique
75
80
  end
76
81
  end
@@ -1,5 +1,5 @@
1
1
  module Flipper
2
- VERSION = '1.2.2'.freeze
2
+ VERSION = '1.3.0'.freeze
3
3
 
4
4
  REQUIRED_RUBY_VERSION = '2.6'.freeze
5
5
  NEXT_REQUIRED_RUBY_VERSION = '3.0'.freeze
@@ -1,5 +1,4 @@
1
1
  SpecHelpers.silence { require 'flipper/adapters/active_record' }
2
- require 'active_support/core_ext/kernel'
3
2
 
4
3
  # Turn off migration logging for specs
5
4
  ActiveRecord::Migration.verbose = false
@@ -17,212 +16,217 @@ RSpec.describe Flipper::Adapters::ActiveRecord do
17
16
 
18
17
  [
19
18
  {
20
- adapter: "sqlite3",
21
- database: ":memory:"
19
+ "adapter" => "sqlite3",
20
+ "database" => ":memory:"
22
21
  },
23
22
 
24
23
  {
25
- adapter: "mysql2",
26
- encoding: "utf8mb4",
27
- username: ENV["MYSQL_USER"] || "root",
28
- password: ENV["MYSQL_PASSWORD"] || "",
29
- database: ENV["MYSQL_DATABASE"] || "flipper_test",
30
- port: ENV["DB_PORT"] || 3306
24
+ "adapter" => "mysql2",
25
+ "encoding" => "utf8mb4",
26
+ "username" => ENV["MYSQL_USER"] || "root",
27
+ "password" => ENV["MYSQL_PASSWORD"] || "",
28
+ "database" => ENV["MYSQL_DATABASE"] || "flipper_test",
29
+ "port" => ENV["DB_PORT"] || 3306
31
30
  },
32
31
 
33
32
  {
34
- adapter: "postgresql",
35
- encoding: "unicode",
36
- host: "127.0.0.1",
37
- username: ENV["POSTGRES_USER"] || "",
38
- password: ENV["POSTGRES_PASSWORD"] || "",
39
- database: ENV["POSTGRES_DATABASE"] || "flipper_test",
33
+ "adapter" => "postgresql",
34
+ "encoding" => "unicode",
35
+ "host" => "127.0.0.1",
36
+ "username" => ENV["POSTGRES_USER"] || "",
37
+ "password" => ENV["POSTGRES_PASSWORD"] || "",
38
+ "database" => ENV["POSTGRES_DATABASE"] || "flipper_test",
40
39
  }
41
40
  ].each do |config|
42
- config = config.with_indifferent_access
43
-
44
- context "with #{config[:adapter]}" do
45
- before(:all) do
46
- silence { ActiveRecord::Tasks::DatabaseTasks.create(config) }
47
- end
48
-
49
- before(:each) do
50
- skip_on_error(ActiveRecord::ConnectionNotEstablished, "#{config[:adapter]} not available") do
51
- ActiveRecord::Base.establish_connection(config)
52
- CreateFlipperTables.migrate(:up)
53
- end
54
- end
55
-
56
- after(:each) do
57
- ActiveRecord::Tasks::DatabaseTasks.purge(config)
58
- ActiveRecord::Base.connection.close
59
- end
60
-
61
- after(:all) do
62
- silence { ActiveRecord::Tasks::DatabaseTasks.drop(config) }
63
- end
64
-
65
- it_should_behave_like 'a flipper adapter'
66
-
67
- it "works when table doesn't exist" do
68
- CreateFlipperTables.migrate(:down)
69
-
70
- Flipper.configuration = nil
71
- Flipper.instance = nil
72
-
73
- expect {
74
- silence do
75
- load 'flipper/adapters/active_record.rb'
76
- Flipper::Adapters::ActiveRecord.new
41
+ context "with #{config['adapter']}" do
42
+ context "with tables created" do
43
+ before(:all) do
44
+ skip_on_error(ActiveRecord::ConnectionNotEstablished, "#{config['adapter']} not available") do
45
+ silence { ActiveRecord::Tasks::DatabaseTasks.create(config) }
77
46
  end
78
- }.not_to raise_error
79
- end
80
-
81
- it "should load actor ids fine" do
82
- flipper.enable_percentage_of_time(:foo, 1)
83
-
84
- Flipper::Adapters::ActiveRecord::Gate.create!(
85
- feature_key: "foo",
86
- key: "actors",
87
- value: "Organization;4",
88
- )
89
47
 
90
- flipper = Flipper.new(subject)
91
- flipper.preload([:foo])
92
- end
93
-
94
- context 'requiring "flipper-active_record"' do
95
- before do
96
48
  Flipper.configuration = nil
97
- Flipper.instance = nil
49
+ end
98
50
 
99
- silence { load 'flipper/adapters/active_record.rb' }
51
+ before(:each) do
52
+ skip_on_error(ActiveRecord::ConnectionNotEstablished, "#{config['adapter']} not available") do
53
+ ActiveRecord::Base.establish_connection(config)
54
+ CreateFlipperTables.migrate(:up)
55
+ end
100
56
  end
101
57
 
102
- it 'configures itself' do
103
- expect(Flipper.adapter.adapter).to be_a(Flipper::Adapters::ActiveRecord)
58
+ after(:each) do
59
+ ActiveRecord::Tasks::DatabaseTasks.purge(config)
60
+ ActiveRecord::Base.connection.close
104
61
  end
105
- end
106
62
 
107
- context "ActiveRecord connection_pool" do
108
- before do
109
- ActiveRecord::Base.clear_active_connections!
63
+ after(:all) do
64
+ silence { ActiveRecord::Tasks::DatabaseTasks.drop(config) } unless $skip
110
65
  end
111
66
 
112
- context "#features" do
113
- it "does not hold onto connections" do
114
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
115
- subject.features
116
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
117
- end
67
+ it_should_behave_like 'a flipper adapter'
118
68
 
119
- it "does not release previously held connection" do
120
- ActiveRecord::Base.connection # establish a new connection
121
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
122
- subject.features
123
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
124
- end
69
+ it "should load actor ids fine" do
70
+ flipper.enable_percentage_of_time(:foo, 1)
71
+
72
+ Flipper::Adapters::ActiveRecord::Gate.create!(
73
+ feature_key: "foo",
74
+ key: "actors",
75
+ value: "Organization;4",
76
+ )
77
+
78
+ flipper = Flipper.new(subject)
79
+ flipper.preload([:foo])
125
80
  end
126
81
 
127
- context "#get_all" do
128
- it "does not hold onto connections" do
129
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
130
- subject.get_all
131
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
82
+ context "ActiveRecord connection_pool" do
83
+ before do
84
+ ActiveRecord::Base.connection_handler.clear_active_connections!
132
85
  end
133
86
 
134
- it "does not release previously held connection" do
135
- ActiveRecord::Base.connection # establish a new connection
136
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
137
- subject.get_all
138
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
87
+ context "#features" do
88
+ it "does not hold onto connections" do
89
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
90
+ subject.features
91
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
92
+ end
93
+
94
+ it "does not release previously held connection" do
95
+ ActiveRecord::Base.connection # establish a new connection
96
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
97
+ subject.features
98
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
99
+ end
139
100
  end
140
- end
141
101
 
142
- context "#add / #remove / #clear" do
143
- let(:feature) { Flipper::Feature.new(:search, subject) }
144
-
145
- it "does not hold onto connections" do
146
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
147
- subject.add(feature)
148
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
149
- subject.remove(feature)
150
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
151
- subject.clear(feature)
152
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
102
+ context "#get_all" do
103
+ it "does not hold onto connections" do
104
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
105
+ subject.get_all
106
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
107
+ end
108
+
109
+ it "does not release previously held connection" do
110
+ ActiveRecord::Base.connection # establish a new connection
111
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
112
+ subject.get_all
113
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
114
+ end
153
115
  end
154
116
 
155
- it "does not release previously held connection" do
156
- ActiveRecord::Base.connection # establish a new connection
157
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
158
- subject.add(feature)
159
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
160
- subject.remove(feature)
161
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
162
- subject.clear(feature)
163
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
117
+ context "#add / #remove / #clear" do
118
+ let(:feature) { Flipper::Feature.new(:search, subject) }
119
+
120
+ it "does not hold onto connections" do
121
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
122
+ subject.add(feature)
123
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
124
+ subject.remove(feature)
125
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
126
+ subject.clear(feature)
127
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
128
+ end
129
+
130
+ it "does not release previously held connection" do
131
+ ActiveRecord::Base.connection # establish a new connection
132
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
133
+ subject.add(feature)
134
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
135
+ subject.remove(feature)
136
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
137
+ subject.clear(feature)
138
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
139
+ end
164
140
  end
165
- end
166
141
 
167
- context "#get_multi" do
168
- let(:feature) { Flipper::Feature.new(:search, subject) }
142
+ context "#get_multi" do
143
+ let(:feature) { Flipper::Feature.new(:search, subject) }
144
+
145
+ it "does not hold onto connections" do
146
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
147
+ subject.get_multi([feature])
148
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
149
+ end
150
+
151
+ it "does not release previously held connection" do
152
+ ActiveRecord::Base.connection # establish a new connection
153
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
154
+ subject.get_multi([feature])
155
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
156
+ end
157
+ end
169
158
 
170
- it "does not hold onto connections" do
171
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
172
- subject.get_multi([feature])
173
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
159
+ context "#enable/#disable boolean" do
160
+ let(:feature) { Flipper::Feature.new(:search, subject) }
161
+ let(:gate) { feature.gate(:boolean)}
162
+
163
+ it "does not hold onto connections" do
164
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
165
+ subject.enable(feature, gate, gate.wrap(true))
166
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
167
+ subject.disable(feature, gate, gate.wrap(false))
168
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
169
+ end
170
+
171
+ it "does not release previously held connection" do
172
+ ActiveRecord::Base.connection # establish a new connection
173
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
174
+ subject.enable(feature, gate, gate.wrap(true))
175
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
176
+ subject.disable(feature, gate, gate.wrap(false))
177
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
178
+ end
174
179
  end
175
180
 
176
- it "does not release previously held connection" do
177
- ActiveRecord::Base.connection # establish a new connection
178
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
179
- subject.get_multi([feature])
180
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
181
+ context "#enable/#disable set" do
182
+ let(:feature) { Flipper::Feature.new(:search, subject) }
183
+ let(:gate) { feature.gate(:group) }
184
+
185
+ it "does not hold onto connections" do
186
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
187
+ subject.enable(feature, gate, gate.wrap(:admin))
188
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
189
+ subject.disable(feature, gate, gate.wrap(:admin))
190
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
191
+ end
192
+
193
+ it "does not release previously held connection" do
194
+ ActiveRecord::Base.connection # establish a new connection
195
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
196
+ subject.enable(feature, gate, gate.wrap(:admin))
197
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
198
+ subject.disable(feature, gate, gate.wrap(:admin))
199
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
200
+ end
181
201
  end
182
202
  end
183
203
 
184
- context "#enable/#disable boolean" do
185
- let(:feature) { Flipper::Feature.new(:search, subject) }
186
- let(:gate) { feature.gate(:boolean)}
204
+ context 'requiring "flipper-active_record"' do
205
+ before do
206
+ Flipper.configuration = nil
207
+ Flipper.instance = nil
187
208
 
188
- it "does not hold onto connections" do
189
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
190
- subject.enable(feature, gate, gate.wrap(true))
191
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
192
- subject.disable(feature, gate, gate.wrap(false))
193
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
209
+ silence { load 'flipper/adapters/active_record.rb' }
194
210
  end
195
211
 
196
- it "does not release previously held connection" do
197
- ActiveRecord::Base.connection # establish a new connection
198
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
199
- subject.enable(feature, gate, gate.wrap(true))
200
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
201
- subject.disable(feature, gate, gate.wrap(false))
202
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
212
+ it 'configures itself' do
213
+ expect(Flipper.adapter.adapter).to be_a(Flipper::Adapters::ActiveRecord)
203
214
  end
204
215
  end
216
+ end
205
217
 
206
- context "#enable/#disable set" do
207
- let(:feature) { Flipper::Feature.new(:search, subject) }
208
- let(:gate) { feature.gate(:group) }
218
+ it "works when table doesn't exist" do
209
219
 
210
- it "does not hold onto connections" do
211
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
212
- subject.enable(feature, gate, gate.wrap(:admin))
213
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
214
- subject.disable(feature, gate, gate.wrap(:admin))
215
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
216
- end
220
+ Flipper.configuration = nil
221
+ Flipper.instance = nil
217
222
 
218
- it "does not release previously held connection" do
219
- ActiveRecord::Base.connection # establish a new connection
220
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
221
- subject.enable(feature, gate, gate.wrap(:admin))
222
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
223
- subject.disable(feature, gate, gate.wrap(:admin))
224
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
225
- end
223
+ Flipper::Adapters.send(:remove_const, :ActiveRecord) if Flipper::Adapters.const_defined?(:ActiveRecord)
224
+
225
+ silence do
226
+ expect {
227
+ load 'flipper/adapters/active_record.rb'
228
+ Flipper::Adapters::ActiveRecord.new
229
+ }.not_to raise_error
226
230
  end
227
231
  end
228
232
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flipper-active_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-19 00:00:00.000000000 Z
11
+ date: 2024-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: flipper
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.2.2
19
+ version: 1.3.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.2.2
26
+ version: 1.3.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -74,7 +74,7 @@ metadata:
74
74
  homepage_uri: https://www.flippercloud.io
75
75
  source_code_uri: https://github.com/flippercloud/flipper
76
76
  bug_tracker_uri: https://github.com/flippercloud/flipper/issues
77
- changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.2.2
77
+ changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.3.0
78
78
  post_install_message:
79
79
  rdoc_options: []
80
80
  require_paths: