flipper-active_record 1.3.0 → 1.3.1
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 +4 -4
- data/lib/flipper/adapters/active_record.rb +47 -40
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/adapters/active_record_spec.rb +49 -18
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e82da07ef8d67f32fbd0bd95cd69cf7fb2c2ab8788ed626b1cd79e6cd6e42329
|
4
|
+
data.tar.gz: 59465c6d945b524f1986a0062f80f0c3eaefdf54974a0800f03b59853edfb1f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e344370f349b7845b02e62a648bdbbd88bf3c335bd1e1c51d8ff0d4d41ed0cd71ee612fa3a0024ef1fc42ac9804b94608f8d3daf11f7ebce33e129d93797ddc
|
7
|
+
data.tar.gz: 86a3dee958e280c3fe2ee35f1fe0f4d29c5a0bcce6f830398bbc851e5d235ed318d10a3031972015834ce0d8c358321ac97d7dcb446e3ee24a3217081390d9d1
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'set'
|
2
|
+
require 'securerandom'
|
2
3
|
require 'flipper'
|
3
4
|
require 'active_record'
|
4
5
|
|
@@ -7,34 +8,36 @@ module Flipper
|
|
7
8
|
class ActiveRecord
|
8
9
|
include ::Flipper::Adapter
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
ActiveSupport.on_load(:active_record) do
|
12
|
+
# Abstract base class for internal models
|
13
|
+
class Model < ::ActiveRecord::Base
|
14
|
+
self.abstract_class = true
|
15
|
+
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
# Private: Do not use outside of this adapter.
|
18
|
+
class Feature < Model
|
19
|
+
self.table_name = [
|
20
|
+
Model.table_name_prefix,
|
21
|
+
"flipper_features",
|
22
|
+
Model.table_name_suffix,
|
23
|
+
].join
|
22
24
|
|
23
|
-
|
25
|
+
has_many :gates, foreign_key: "feature_key", primary_key: "key"
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
+
validates :key, presence: true
|
28
|
+
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
# Private: Do not use outside of this adapter.
|
31
|
+
class Gate < Model
|
32
|
+
self.table_name = [
|
33
|
+
Model.table_name_prefix,
|
34
|
+
"flipper_gates",
|
35
|
+
Model.table_name_suffix,
|
36
|
+
].join
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
+
validates :feature_key, presence: true
|
39
|
+
validates :key, presence: true
|
40
|
+
end
|
38
41
|
end
|
39
42
|
|
40
43
|
VALUE_TO_TEXT_WARNING = <<-EOS
|
@@ -70,14 +73,15 @@ module Flipper
|
|
70
73
|
# Public: Adds a feature to the set of known features.
|
71
74
|
def add(feature)
|
72
75
|
with_connection(@feature_class) do
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
76
|
+
@feature_class.transaction(requires_new: true) do
|
77
|
+
begin
|
78
|
+
# race condition, but add is only used by enable/disable which happen
|
79
|
+
# super rarely, so it shouldn't matter in practice
|
80
|
+
unless @feature_class.where(key: feature.key).exists?
|
78
81
|
@feature_class.create!(key: feature.key)
|
79
|
-
rescue ::ActiveRecord::RecordNotUnique
|
80
82
|
end
|
83
|
+
rescue ::ActiveRecord::RecordNotUnique
|
84
|
+
# already added
|
81
85
|
end
|
82
86
|
end
|
83
87
|
end
|
@@ -128,14 +132,14 @@ module Flipper
|
|
128
132
|
end
|
129
133
|
|
130
134
|
def get_all
|
131
|
-
with_connection(@feature_class) do
|
135
|
+
with_connection(@feature_class) do |connection|
|
132
136
|
# query the gates from the db in a single query
|
133
137
|
features = ::Arel::Table.new(@feature_class.table_name.to_sym)
|
134
138
|
gates = ::Arel::Table.new(@gate_class.table_name.to_sym)
|
135
139
|
rows_query = features.join(gates, ::Arel::Nodes::OuterJoin)
|
136
140
|
.on(features[:key].eq(gates[:feature_key]))
|
137
141
|
.project(features[:key].as('feature_key'), gates[:key], gates[:value])
|
138
|
-
gates =
|
142
|
+
gates = connection.select_rows(rows_query)
|
139
143
|
|
140
144
|
# group the gates by feature key
|
141
145
|
grouped_gates = gates.inject({}) do |hash, (feature_key, key, value)|
|
@@ -218,10 +222,9 @@ module Flipper
|
|
218
222
|
raise VALUE_TO_TEXT_WARNING if json_feature && value_not_text?
|
219
223
|
|
220
224
|
with_connection(@gate_class) do
|
221
|
-
@gate_class.transaction do
|
225
|
+
@gate_class.transaction(requires_new: true) do
|
222
226
|
clear(feature) if clear_feature
|
223
227
|
delete(feature, gate)
|
224
|
-
@gate_class.where(feature_key: feature.key, key: gate.key).destroy_all
|
225
228
|
begin
|
226
229
|
@gate_class.create! do |g|
|
227
230
|
g.feature_key = feature.key
|
@@ -243,17 +246,21 @@ module Flipper
|
|
243
246
|
end
|
244
247
|
|
245
248
|
def enable_multi(feature, gate, thing)
|
246
|
-
with_connection(@gate_class) do
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
249
|
+
with_connection(@gate_class) do |connection|
|
250
|
+
begin
|
251
|
+
connection.transaction(requires_new: true) do
|
252
|
+
@gate_class.create! do |g|
|
253
|
+
g.feature_key = feature.key
|
254
|
+
g.key = gate.key
|
255
|
+
g.value = thing.value.to_s
|
256
|
+
end
|
257
|
+
end
|
258
|
+
rescue ::ActiveRecord::RecordNotUnique
|
259
|
+
# already added so move on with life
|
251
260
|
end
|
252
261
|
end
|
253
262
|
|
254
263
|
nil
|
255
|
-
rescue ::ActiveRecord::RecordNotUnique
|
256
|
-
# already added so no need move on with life
|
257
264
|
end
|
258
265
|
|
259
266
|
def result_for_gates(feature, gates)
|
data/lib/flipper/version.rb
CHANGED
@@ -23,6 +23,7 @@ RSpec.describe Flipper::Adapters::ActiveRecord do
|
|
23
23
|
{
|
24
24
|
"adapter" => "mysql2",
|
25
25
|
"encoding" => "utf8mb4",
|
26
|
+
"host" => ENV["MYSQL_HOST"],
|
26
27
|
"username" => ENV["MYSQL_USER"] || "root",
|
27
28
|
"password" => ENV["MYSQL_PASSWORD"] || "",
|
28
29
|
"database" => ENV["MYSQL_DATABASE"] || "flipper_test",
|
@@ -42,22 +43,17 @@ RSpec.describe Flipper::Adapters::ActiveRecord do
|
|
42
43
|
context "with tables created" do
|
43
44
|
before(:all) do
|
44
45
|
skip_on_error(ActiveRecord::ConnectionNotEstablished, "#{config['adapter']} not available") do
|
45
|
-
silence
|
46
|
+
silence do
|
47
|
+
ActiveRecord::Tasks::DatabaseTasks.create(config)
|
48
|
+
end
|
46
49
|
end
|
47
50
|
|
48
51
|
Flipper.configuration = nil
|
49
52
|
end
|
50
53
|
|
51
54
|
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
|
56
|
-
end
|
57
|
-
|
58
|
-
after(:each) do
|
59
55
|
ActiveRecord::Tasks::DatabaseTasks.purge(config)
|
60
|
-
|
56
|
+
CreateFlipperTables.migrate(:up)
|
61
57
|
end
|
62
58
|
|
63
59
|
after(:all) do
|
@@ -79,6 +75,20 @@ RSpec.describe Flipper::Adapters::ActiveRecord do
|
|
79
75
|
flipper.preload([:foo])
|
80
76
|
end
|
81
77
|
|
78
|
+
it 'should not poison wrapping transactions' do
|
79
|
+
flipper = Flipper.new(subject)
|
80
|
+
|
81
|
+
actor = Struct.new(:flipper_id).new('flipper-id-123')
|
82
|
+
flipper.enable_actor(:foo, actor)
|
83
|
+
|
84
|
+
ActiveRecord::Base.transaction do
|
85
|
+
flipper.enable_actor(:foo, actor)
|
86
|
+
# any read on the next line is fine, just need to ensure that
|
87
|
+
# poisoned transaction isn't raised
|
88
|
+
expect(Flipper::Adapters::ActiveRecord::Gate.count).to eq(1)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
82
92
|
context "ActiveRecord connection_pool" do
|
83
93
|
before do
|
84
94
|
ActiveRecord::Base.connection_handler.clear_active_connections!
|
@@ -215,18 +225,39 @@ RSpec.describe Flipper::Adapters::ActiveRecord do
|
|
215
225
|
end
|
216
226
|
end
|
217
227
|
|
218
|
-
|
228
|
+
context "without tables created" do
|
229
|
+
before(:all) do
|
230
|
+
skip_on_error(ActiveRecord::ConnectionNotEstablished, "#{config['adapter']} not available") do
|
231
|
+
silence do
|
232
|
+
ActiveRecord::Tasks::DatabaseTasks.create(config)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
Flipper.configuration = nil
|
237
|
+
end
|
238
|
+
|
239
|
+
before(:each) do
|
240
|
+
ActiveRecord::Base.establish_connection(config)
|
241
|
+
end
|
242
|
+
|
243
|
+
after(:each) do
|
244
|
+
ActiveRecord::Base.connection.close
|
245
|
+
end
|
219
246
|
|
220
|
-
|
221
|
-
|
247
|
+
after(:all) do
|
248
|
+
silence { ActiveRecord::Tasks::DatabaseTasks.drop(config) } unless $skip
|
249
|
+
end
|
222
250
|
|
223
|
-
|
251
|
+
it "does not raise an error" do
|
252
|
+
Flipper.configuration = nil
|
253
|
+
Flipper.instance = nil
|
224
254
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
255
|
+
silence do
|
256
|
+
expect {
|
257
|
+
load 'flipper/adapters/active_record.rb'
|
258
|
+
Flipper::Adapters::ActiveRecord.new
|
259
|
+
}.not_to raise_error
|
260
|
+
end
|
230
261
|
end
|
231
262
|
end
|
232
263
|
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.3.
|
4
|
+
version: 1.3.1
|
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-04
|
11
|
+
date: 2024-09-04 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.3.
|
19
|
+
version: 1.3.1
|
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.3.
|
26
|
+
version: 1.3.1
|
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.3.
|
77
|
+
changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.3.1
|
78
78
|
post_install_message:
|
79
79
|
rdoc_options: []
|
80
80
|
require_paths:
|
@@ -90,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
90
|
- !ruby/object:Gem::Version
|
91
91
|
version: '0'
|
92
92
|
requirements: []
|
93
|
-
rubygems_version: 3.5.
|
93
|
+
rubygems_version: 3.5.18
|
94
94
|
signing_key:
|
95
95
|
specification_version: 4
|
96
96
|
summary: ActiveRecord feature flag adapter for Flipper
|