flipper-active_record 1.1.1 → 1.1.2

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