flipper-active_record 1.3.0.pre → 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 +49 -37
- 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,29 +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
|
-
|
24
|
-
|
25
|
+
has_many :gates, foreign_key: "feature_key", primary_key: "key"
|
26
|
+
|
27
|
+
validates :key, presence: true
|
28
|
+
end
|
25
29
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
37
|
+
|
38
|
+
validates :feature_key, presence: true
|
39
|
+
validates :key, presence: true
|
40
|
+
end
|
33
41
|
end
|
34
42
|
|
35
43
|
VALUE_TO_TEXT_WARNING = <<-EOS
|
@@ -65,14 +73,15 @@ module Flipper
|
|
65
73
|
# Public: Adds a feature to the set of known features.
|
66
74
|
def add(feature)
|
67
75
|
with_connection(@feature_class) do
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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?
|
73
81
|
@feature_class.create!(key: feature.key)
|
74
|
-
rescue ::ActiveRecord::RecordNotUnique
|
75
82
|
end
|
83
|
+
rescue ::ActiveRecord::RecordNotUnique
|
84
|
+
# already added
|
76
85
|
end
|
77
86
|
end
|
78
87
|
end
|
@@ -123,14 +132,14 @@ module Flipper
|
|
123
132
|
end
|
124
133
|
|
125
134
|
def get_all
|
126
|
-
with_connection(@feature_class) do
|
135
|
+
with_connection(@feature_class) do |connection|
|
127
136
|
# query the gates from the db in a single query
|
128
137
|
features = ::Arel::Table.new(@feature_class.table_name.to_sym)
|
129
138
|
gates = ::Arel::Table.new(@gate_class.table_name.to_sym)
|
130
139
|
rows_query = features.join(gates, ::Arel::Nodes::OuterJoin)
|
131
140
|
.on(features[:key].eq(gates[:feature_key]))
|
132
141
|
.project(features[:key].as('feature_key'), gates[:key], gates[:value])
|
133
|
-
gates =
|
142
|
+
gates = connection.select_rows(rows_query)
|
134
143
|
|
135
144
|
# group the gates by feature key
|
136
145
|
grouped_gates = gates.inject({}) do |hash, (feature_key, key, value)|
|
@@ -213,10 +222,9 @@ module Flipper
|
|
213
222
|
raise VALUE_TO_TEXT_WARNING if json_feature && value_not_text?
|
214
223
|
|
215
224
|
with_connection(@gate_class) do
|
216
|
-
@gate_class.transaction do
|
225
|
+
@gate_class.transaction(requires_new: true) do
|
217
226
|
clear(feature) if clear_feature
|
218
227
|
delete(feature, gate)
|
219
|
-
@gate_class.where(feature_key: feature.key, key: gate.key).destroy_all
|
220
228
|
begin
|
221
229
|
@gate_class.create! do |g|
|
222
230
|
g.feature_key = feature.key
|
@@ -238,17 +246,21 @@ module Flipper
|
|
238
246
|
end
|
239
247
|
|
240
248
|
def enable_multi(feature, gate, thing)
|
241
|
-
with_connection(@gate_class) do
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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
|
246
260
|
end
|
247
261
|
end
|
248
262
|
|
249
263
|
nil
|
250
|
-
rescue ::ActiveRecord::RecordNotUnique
|
251
|
-
# already added so no need move on with life
|
252
264
|
end
|
253
265
|
|
254
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-
|
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
|