flipper-active_record 1.1.1 → 1.1.2

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: e7440c16ba96d1af13b04d53af4a794f2b2721ac9073f3be79399542d35f0e8b
4
- data.tar.gz: 3bf38ab6f14dcf13cfaa53e1d8cfba1622be76cbd0cbb26313c2b135d9681b64
3
+ metadata.gz: a87a99a5d26e8ffd53a4e4620612f5babe97090fc9a25a13999cbeef90eb38c3
4
+ data.tar.gz: 4e2523ba1ddd2b72c383893ba161655526292334fb8a3f863891c7a2ae7dbd2b
5
5
  SHA512:
6
- metadata.gz: ae73ab2931ebaa6ab45e8f12d75fd16859b7c35fe83c09311b51c3dd43243106db50588dd7605f9e98a8d1611305861fcf3f082561b06dceab042d21f67e56fd
7
- data.tar.gz: 707051b6ad52cbbe0a50e817ba06d39ddb30cc42c1f7585e890d4c4f378bbd8775e519212cf38c43fe49907245c3e25da618e3644081dc5afcca3056d7b90b8b
6
+ metadata.gz: 80587a110384c5ac2e4d11e143ad33797d092b391f6e553b87cd2499dc841dfb75079eb414368470400709ede4fa3c96e12416c48712cd731a4606da50f63b9f
7
+ data.tar.gz: ec0a0d89da664ae8aedc701a7406a2794391d27987bcc0ce85be3a33e1b2c02b76869206301f49d1c9489c703cd9de47c0b6714b166cd758805996569e25e355
@@ -16,7 +16,7 @@ end
16
16
  Gem::Specification.new do |gem|
17
17
  gem.authors = ['John Nunemaker']
18
18
  gem.email = 'support@flippercloud.io'
19
- gem.summary = 'ActiveRecord adapter for Flipper'
19
+ gem.summary = 'ActiveRecord feature flag adapter for Flipper'
20
20
  gem.license = 'MIT'
21
21
  gem.homepage = 'https://www.flippercloud.io/docs/adapters/active-record'
22
22
 
@@ -34,7 +34,7 @@ module Flipper
34
34
 
35
35
  VALUE_TO_TEXT_WARNING = <<-EOS
36
36
  Your database needs migrated to use the latest Flipper features.
37
- See https://github.com/flippercloud/flipper/issues/557
37
+ Run `rails generate flipper:update` and `rails db:migrate`.
38
38
  EOS
39
39
 
40
40
  # Public: Initialize a new ActiveRecord adapter instance.
@@ -278,6 +278,9 @@ module Flipper
278
278
  # See https://github.com/flippercloud/flipper/pull/692
279
279
  def value_not_text?
280
280
  @gate_class.column_for_attribute(:value).type != :text
281
+ rescue ::ActiveRecord::ActiveRecordError => error
282
+ # If the table doesn't exist, the column doesn't exist either
283
+ warn "#{error.message}. You likely need to run `rails g flipper:active_record` and/or `rails db:migrate`."
281
284
  end
282
285
 
283
286
  def with_connection(model = @feature_class, &block)
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '1.1.1'.freeze
2
+ VERSION = '1.1.2'.freeze
3
3
  end
@@ -1,5 +1,5 @@
1
1
  class CreateFlipperTables < ActiveRecord::Migration<%= migration_version %>
2
- def self.up
2
+ def up
3
3
  create_table :flipper_features do |t|
4
4
  t.string :key, null: false
5
5
  t.timestamps null: false
@@ -12,10 +12,10 @@ class CreateFlipperTables < ActiveRecord::Migration<%= migration_version %>
12
12
  t.text :value
13
13
  t.timestamps null: false
14
14
  end
15
- add_index :flipper_gates, [:feature_key, :key, :value], unique: true
15
+ add_index :flipper_gates, [:feature_key, :key, :value], unique: true, length: { value: 255 }
16
16
  end
17
17
 
18
- def self.down
18
+ def down
19
19
  drop_table :flipper_gates
20
20
  drop_table :flipper_features
21
21
  end
@@ -3,191 +3,223 @@ require 'active_support/core_ext/kernel'
3
3
 
4
4
  # Turn off migration logging for specs
5
5
  ActiveRecord::Migration.verbose = false
6
+ ActiveRecord::Tasks::DatabaseTasks.root = File.dirname(__FILE__)
6
7
 
7
8
  RSpec.describe Flipper::Adapters::ActiveRecord do
8
9
  subject { described_class.new }
9
10
 
10
11
  before(:all) do
11
- ActiveRecord::Base.establish_connection(adapter: 'sqlite3',
12
- database: ':memory:')
12
+ # Eval migration template so we can run migration against each database
13
+ migration = ERB.new(File.read(File.join(File.dirname(__FILE__), '../../../lib/generators/flipper/templates/migration.erb')))
14
+ migration_version = "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
15
+ eval migration.result(binding) # defines CreateFlipperTables
13
16
  end
14
17
 
15
- before(:each) do
16
- ActiveRecord::Base.connection.execute <<-SQL
17
- CREATE TABLE flipper_features (
18
- id integer PRIMARY KEY,
19
- key string NOT NULL UNIQUE,
20
- created_at datetime NOT NULL,
21
- updated_at datetime NOT NULL
22
- )
23
- SQL
24
-
25
- ActiveRecord::Base.connection.execute <<-SQL
26
- CREATE TABLE flipper_gates (
27
- id integer PRIMARY KEY,
28
- feature_key text NOT NULL,
29
- key string NOT NULL,
30
- value text DEFAULT NULL,
31
- created_at datetime NOT NULL,
32
- updated_at datetime NOT NULL
33
- )
34
- SQL
35
-
36
- ActiveRecord::Base.connection.execute <<-SQL
37
- CREATE UNIQUE INDEX index_gates_on_keys_and_value on flipper_gates (feature_key, key, value)
38
- SQL
39
- end
40
-
41
- after(:each) do
42
- ActiveRecord::Base.connection.execute("DROP table IF EXISTS `flipper_features`")
43
- ActiveRecord::Base.connection.execute("DROP table IF EXISTS `flipper_gates`")
44
- end
45
-
46
- it_should_behave_like 'a flipper adapter'
47
-
48
- it "should load actor ids fine" do
49
- flipper.enable_percentage_of_time(:foo, 1)
50
-
51
- ActiveRecord::Base.connection.execute <<-SQL
52
- INSERT INTO flipper_gates (feature_key, key, value, created_at, updated_at)
53
- VALUES ("foo", "actors", "Organization;4", time(), time())
54
- SQL
55
-
56
- flipper = Flipper.new(subject)
57
- flipper.preload([:foo])
58
- end
59
-
60
- context 'requiring "flipper-active_record"' do
61
- before do
62
- Flipper.configuration = nil
63
- Flipper.instance = nil
64
-
65
- silence_warnings { load 'flipper/adapters/active_record.rb' }
66
- end
67
-
68
- it 'configures itself' do
69
- expect(Flipper.adapter.adapter).to be_a(Flipper::Adapters::ActiveRecord)
70
- end
71
- end
72
-
73
- context "ActiveRecord connection_pool" do
74
- before do
75
- ActiveRecord::Base.clear_active_connections!
76
- end
77
-
78
- context "#features" do
79
- it "does not hold onto connections" do
80
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
81
- subject.features
82
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
18
+ [
19
+ {
20
+ adapter: "sqlite3",
21
+ database: ":memory:"
22
+ },
23
+
24
+ {
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
31
+ },
32
+
33
+ {
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",
40
+ }
41
+ ].each do |config|
42
+ config = config.with_indifferent_access
43
+
44
+ context "with #{config[:adapter]}" do
45
+ before(:all) do
46
+ ActiveRecord::Tasks::DatabaseTasks.create(config)
83
47
  end
84
48
 
85
- it "does not release previously held connection" do
86
- ActiveRecord::Base.connection # establish a new connection
87
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
88
- subject.features
89
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
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
90
54
  end
91
- end
92
55
 
93
- context "#get_all" do
94
- it "does not hold onto connections" do
95
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
96
- subject.get_all
97
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
56
+ after(:each) do
57
+ ActiveRecord::Tasks::DatabaseTasks.purge(config)
58
+ ActiveRecord::Base.connection.close
98
59
  end
99
60
 
100
- it "does not release previously held connection" do
101
- ActiveRecord::Base.connection # establish a new connection
102
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
103
- subject.get_all
104
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
61
+ after(:all) do
62
+ ActiveRecord::Tasks::DatabaseTasks.drop(config)
105
63
  end
106
- end
107
64
 
108
- context "#add / #remove / #clear" do
109
- let(:feature) { Flipper::Feature.new(:search, subject) }
110
-
111
- it "does not hold onto connections" do
112
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
113
- subject.add(feature)
114
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
115
- subject.remove(feature)
116
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
117
- subject.clear(feature)
118
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
119
- end
65
+ it_should_behave_like 'a flipper adapter'
120
66
 
121
- it "does not release previously held connection" do
122
- ActiveRecord::Base.connection # establish a new connection
123
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
124
- subject.add(feature)
125
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
126
- subject.remove(feature)
127
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
128
- subject.clear(feature)
129
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
130
- end
131
- end
67
+ it "works when table doesn't exist" do
68
+ CreateFlipperTables.migrate(:down)
132
69
 
133
- context "#get_multi" do
134
- let(:feature) { Flipper::Feature.new(:search, subject) }
70
+ Flipper.configuration = nil
71
+ Flipper.instance = nil
135
72
 
136
- it "does not hold onto connections" do
137
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
138
- subject.get_multi([feature])
139
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
73
+ silence_warnings { load 'flipper/adapters/active_record.rb' }
74
+ expect { Flipper::Adapters::ActiveRecord.new }.not_to raise_error
140
75
  end
141
76
 
142
- it "does not release previously held connection" do
143
- ActiveRecord::Base.connection # establish a new connection
144
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
145
- subject.get_multi([feature])
146
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
147
- end
148
- end
77
+ it "should load actor ids fine" do
78
+ flipper.enable_percentage_of_time(:foo, 1)
149
79
 
150
- context "#enable/#disable boolean" do
151
- let(:feature) { Flipper::Feature.new(:search, subject) }
152
- let(:gate) { feature.gate(:boolean)}
80
+ Flipper::Adapters::ActiveRecord::Gate.create!(
81
+ feature_key: "foo",
82
+ key: "actors",
83
+ value: "Organization;4",
84
+ )
153
85
 
154
- it "does not hold onto connections" do
155
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
156
- subject.enable(feature, gate, gate.wrap(true))
157
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
158
- subject.disable(feature, gate, gate.wrap(false))
159
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
86
+ flipper = Flipper.new(subject)
87
+ flipper.preload([:foo])
160
88
  end
161
89
 
162
- it "does not release previously held connection" do
163
- ActiveRecord::Base.connection # establish a new connection
164
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
165
- subject.enable(feature, gate, gate.wrap(true))
166
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
167
- subject.disable(feature, gate, gate.wrap(false))
168
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
169
- end
170
- end
90
+ context 'requiring "flipper-active_record"' do
91
+ before do
92
+ Flipper.configuration = nil
93
+ Flipper.instance = nil
171
94
 
172
- context "#enable/#disable set" do
173
- let(:feature) { Flipper::Feature.new(:search, subject) }
174
- let(:gate) { feature.gate(:group) }
95
+ silence_warnings { load 'flipper/adapters/active_record.rb' }
96
+ end
175
97
 
176
- it "does not hold onto connections" do
177
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
178
- subject.enable(feature, gate, gate.wrap(:admin))
179
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
180
- subject.disable(feature, gate, gate.wrap(:admin))
181
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
98
+ it 'configures itself' do
99
+ expect(Flipper.adapter.adapter).to be_a(Flipper::Adapters::ActiveRecord)
100
+ end
182
101
  end
183
102
 
184
- it "does not release previously held connection" do
185
- ActiveRecord::Base.connection # establish a new connection
186
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
187
- subject.enable(feature, gate, gate.wrap(:admin))
188
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
189
- subject.disable(feature, gate, gate.wrap(:admin))
190
- expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
103
+ context "ActiveRecord connection_pool" do
104
+ before do
105
+ ActiveRecord::Base.clear_active_connections!
106
+ end
107
+
108
+ context "#features" do
109
+ it "does not hold onto connections" do
110
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
111
+ subject.features
112
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
113
+ end
114
+
115
+ it "does not release previously held connection" do
116
+ ActiveRecord::Base.connection # establish a new connection
117
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
118
+ subject.features
119
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
120
+ end
121
+ end
122
+
123
+ context "#get_all" do
124
+ it "does not hold onto connections" do
125
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
126
+ subject.get_all
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.get_all
134
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
135
+ end
136
+ end
137
+
138
+ context "#add / #remove / #clear" do
139
+ let(:feature) { Flipper::Feature.new(:search, subject) }
140
+
141
+ it "does not hold onto connections" do
142
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
143
+ subject.add(feature)
144
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
145
+ subject.remove(feature)
146
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
147
+ subject.clear(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.add(feature)
155
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
156
+ subject.remove(feature)
157
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
158
+ subject.clear(feature)
159
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
160
+ end
161
+ end
162
+
163
+ context "#get_multi" do
164
+ let(:feature) { Flipper::Feature.new(:search, subject) }
165
+
166
+ it "does not hold onto connections" do
167
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
168
+ subject.get_multi([feature])
169
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
170
+ end
171
+
172
+ it "does not release previously held connection" do
173
+ ActiveRecord::Base.connection # establish a new connection
174
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
175
+ subject.get_multi([feature])
176
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
177
+ end
178
+ end
179
+
180
+ context "#enable/#disable boolean" do
181
+ let(:feature) { Flipper::Feature.new(:search, subject) }
182
+ let(:gate) { feature.gate(:boolean)}
183
+
184
+ it "does not hold onto connections" do
185
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
186
+ subject.enable(feature, gate, gate.wrap(true))
187
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
188
+ subject.disable(feature, gate, gate.wrap(false))
189
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
190
+ end
191
+
192
+ it "does not release previously held connection" do
193
+ ActiveRecord::Base.connection # establish a new connection
194
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
195
+ subject.enable(feature, gate, gate.wrap(true))
196
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
197
+ subject.disable(feature, gate, gate.wrap(false))
198
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
199
+ end
200
+ end
201
+
202
+ context "#enable/#disable set" do
203
+ let(:feature) { Flipper::Feature.new(:search, subject) }
204
+ let(:gate) { feature.gate(:group) }
205
+
206
+ it "does not hold onto connections" do
207
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
208
+ subject.enable(feature, gate, gate.wrap(:admin))
209
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
210
+ subject.disable(feature, gate, gate.wrap(:admin))
211
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(false)
212
+ end
213
+
214
+ it "does not release previously held connection" do
215
+ ActiveRecord::Base.connection # establish a new connection
216
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
217
+ subject.enable(feature, gate, gate.wrap(:admin))
218
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
219
+ subject.disable(feature, gate, gate.wrap(:admin))
220
+ expect(ActiveRecord::Base.connection_handler.active_connections?).to be(true)
221
+ end
222
+ end
191
223
  end
192
224
  end
193
225
  end
@@ -1,5 +1,4 @@
1
- require 'active_record'
2
- require 'rails/generators/test_case'
1
+ require 'helper'
3
2
  require 'generators/flipper/active_record_generator'
4
3
 
5
4
  class FlipperActiveRecordGeneratorTest < Rails::Generators::TestCase
@@ -16,7 +15,7 @@ class FlipperActiveRecordGeneratorTest < Rails::Generators::TestCase
16
15
  end
17
16
  assert_migration 'db/migrate/create_flipper_tables.rb', <<~MIGRATION
18
17
  class CreateFlipperTables < ActiveRecord::Migration#{migration_version}
19
- def self.up
18
+ def up
20
19
  create_table :flipper_features do |t|
21
20
  t.string :key, null: false
22
21
  t.timestamps null: false
@@ -26,13 +25,13 @@ class FlipperActiveRecordGeneratorTest < Rails::Generators::TestCase
26
25
  create_table :flipper_gates do |t|
27
26
  t.string :feature_key, null: false
28
27
  t.string :key, null: false
29
- t.string :value
28
+ t.text :value
30
29
  t.timestamps null: false
31
30
  end
32
- add_index :flipper_gates, [:feature_key, :key, :value], unique: true
31
+ add_index :flipper_gates, [:feature_key, :key, :value], unique: true, length: { value: 255 }
33
32
  end
34
33
 
35
- def self.down
34
+ def down
36
35
  drop_table :flipper_gates
37
36
  drop_table :flipper_features
38
37
  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.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-09 00:00:00.000000000 Z
11
+ date: 2023-12-12 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.1.1
19
+ version: 1.1.2
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.1.1
26
+ version: 1.1.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -93,7 +93,7 @@ requirements: []
93
93
  rubygems_version: 3.4.10
94
94
  signing_key:
95
95
  specification_version: 4
96
- summary: ActiveRecord adapter for Flipper
96
+ summary: ActiveRecord feature flag adapter for Flipper
97
97
  test_files:
98
98
  - spec/flipper/adapters/active_record_spec.rb
99
99
  - test/adapters/active_record_test.rb