flipper-active_record 0.26.1 → 0.27.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: 5244fa15983cbfcba71bcf8d555d71d3e9142314d035dc7dad084ea413d0abfd
4
- data.tar.gz: 810a08e5c66d66765f8a09e5b4554804792200b0fa8084fd38bb12a2db44cb08
3
+ metadata.gz: f1ec7d9f3d54551e8b6085d9105c854f96dfe8f6ac0d9b7840652e7f2882ee3c
4
+ data.tar.gz: 8d28946c836b4b405f522b4ae703659cdd8ba4194024098ffc9d4a9239821744
5
5
  SHA512:
6
- metadata.gz: 20d45ea8dc75cbab5be320ea9ca22487f7a15483088c2370d48bb0e1b01e1fbf6cb657f9cd3f17ffd02c4fbeef1e20a80d3f328eb5a29d03961ddbfc87bd1439
7
- data.tar.gz: 5d3871e886483ee2c9cefa90ef1fb918b4fd795c46121251b62c4c7543868578ba519f6f9547a58a749c87f4840e09496ef9c403f1765b91851be8bfd44c5d6b
6
+ metadata.gz: 772e0c2625811d8edfeed372c5a79ee3518328791e73ef86ad0dc4bc7093e9e53d2ae907b1a6a19be81a482e6f1f1ddd4edfe32a58b0f063e9c719d8c7f61083
7
+ data.tar.gz: 8023576edb27c613d508884adf287e04f8305c20b7d8e0c36718fa37979e122da6342234db984751c05fb607dd1d5151048913ff25e2751d4c08acff0850e083
@@ -0,0 +1,15 @@
1
+ require 'bundler/setup'
2
+ require_relative './active_record_setup'
3
+ require 'flipper'
4
+ require 'flipper/adapters/active_record'
5
+ require 'benchmark/ips'
6
+
7
+ flipper = Flipper.new(Flipper::Adapters::ActiveRecord.new)
8
+
9
+ 2000.times do |i|
10
+ flipper.enable_actor :foo, Flipper::Actor.new("User;#{i}")
11
+ end
12
+
13
+ Benchmark.ips do |x|
14
+ x.report("get_all") { flipper.preload_all }
15
+ end
@@ -0,0 +1,17 @@
1
+ require 'bundler/setup'
2
+ require_relative './active_record_setup'
3
+ require 'flipper'
4
+ require 'flipper/adapters/active_record'
5
+ require 'benchmark/ips'
6
+
7
+ flipper = Flipper.new(Flipper::Adapters::ActiveRecord.new)
8
+
9
+ 2000.times do |i|
10
+ flipper.enable_actor :foo, Flipper::Actor.new("User;#{i}")
11
+ end
12
+
13
+ Benchmark.ips do |x|
14
+ x.report("all") { Flipper::Adapters::ActiveRecord::Gate.where(feature_key: "foo".freeze).load }
15
+ x.report("pluck") { Flipper::Adapters::ActiveRecord::Gate.where(feature_key: "foo".freeze).pluck(:key, :value) }
16
+ x.compare!
17
+ end
@@ -0,0 +1,31 @@
1
+ require 'bundler/setup'
2
+ require 'active_record'
3
+
4
+ ActiveRecord::Base.establish_connection({
5
+ adapter: 'sqlite3',
6
+ database: ':memory:',
7
+ })
8
+
9
+ ActiveRecord::Base.connection.execute <<-SQL
10
+ CREATE TABLE flipper_features (
11
+ id integer PRIMARY KEY,
12
+ key text NOT NULL UNIQUE,
13
+ created_at datetime NOT NULL,
14
+ updated_at datetime NOT NULL
15
+ )
16
+ SQL
17
+
18
+ ActiveRecord::Base.connection.execute <<-SQL
19
+ CREATE TABLE flipper_gates (
20
+ id integer PRIMARY KEY,
21
+ feature_key text NOT NULL,
22
+ key text NOT NULL,
23
+ value text DEFAULT NULL,
24
+ created_at datetime NOT NULL,
25
+ updated_at datetime NOT NULL
26
+ )
27
+ SQL
28
+
29
+ ActiveRecord::Base.connection.execute <<-SQL
30
+ CREATE UNIQUE INDEX index_gates_on_keys_and_value on flipper_gates (feature_key, key, value)
31
+ SQL
@@ -0,0 +1,23 @@
1
+ require_relative "./ar_setup"
2
+
3
+ # Requires the flipper-active_record gem to be installed.
4
+ require 'flipper/adapters/active_record'
5
+ require 'flipper/adapters/active_support_cache_store'
6
+
7
+ Flipper.configure do |config|
8
+ config.adapter do
9
+ Flipper::Adapters::ActiveSupportCacheStore.new(
10
+ Flipper::Adapters::ActiveRecord.new,
11
+ ActiveSupport::Cache::MemoryStore.new,
12
+ expires_in: 2.seconds
13
+ )
14
+ end
15
+ end
16
+
17
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
18
+
19
+ puts "You should see 5 or 6 queries."
20
+ 10.times do |i|
21
+ Flipper.enabled?(:foo)
22
+ sleep 1
23
+ end
@@ -95,17 +95,22 @@ module Flipper
95
95
  #
96
96
  # Returns a Hash of Flipper::Gate#key => value.
97
97
  def get(feature)
98
- db_gates = with_connection(@gate_class) { @gate_class.where(feature_key: feature.key) }
99
- result_for_feature(feature, db_gates)
98
+ gates = with_connection(@gate_class) { @gate_class.where(feature_key: feature.key).pluck(:key, :value) }
99
+ result_for_gates(feature, gates)
100
100
  end
101
101
 
102
102
  def get_multi(features)
103
103
  with_connection(@gate_class) do
104
- db_gates = @gate_class.where(feature_key: features.map(&:key))
105
- grouped_db_gates = db_gates.group_by(&:feature_key)
104
+ gates = @gate_class.where(feature_key: features.map(&:key)).pluck(:feature_key, :key, :value)
105
+ grouped_gates = gates.inject({}) do |hash, (feature_key, key, value)|
106
+ hash[feature_key] ||= []
107
+ hash[feature_key] << [key, value]
108
+ hash
109
+ end
110
+
106
111
  result = {}
107
112
  features.each do |feature|
108
- result[feature.key] = result_for_feature(feature, grouped_db_gates[feature.key])
113
+ result[feature.key] = result_for_gates(feature, grouped_gates[feature.key])
109
114
  end
110
115
  result
111
116
  end
@@ -113,18 +118,26 @@ module Flipper
113
118
 
114
119
  def get_all
115
120
  with_connection(@feature_class) do
121
+ # query the gates from the db in a single query
116
122
  features = ::Arel::Table.new(@feature_class.table_name.to_sym)
117
123
  gates = ::Arel::Table.new(@gate_class.table_name.to_sym)
118
- rows_query = features.join(gates, Arel::Nodes::OuterJoin)
124
+ rows_query = features.join(gates, ::Arel::Nodes::OuterJoin)
119
125
  .on(features[:key].eq(gates[:feature_key]))
120
126
  .project(features[:key].as('feature_key'), gates[:key], gates[:value])
121
- rows = @feature_class.connection.select_all rows_query
122
- db_gates = rows.map { |row| @gate_class.new(row) }
123
- grouped_db_gates = db_gates.group_by(&:feature_key)
127
+ gates = @feature_class.connection.select_rows(rows_query)
128
+
129
+ # group the gates by feature key
130
+ grouped_gates = gates.inject({}) do |hash, (feature_key, key, value)|
131
+ hash[feature_key] ||= []
132
+ hash[feature_key] << [key, value]
133
+ hash
134
+ end
135
+
136
+ # build up the result hash
124
137
  result = Hash.new { |hash, key| hash[key] = default_config }
125
- features = grouped_db_gates.keys.map { |key| Flipper::Feature.new(key, self) }
138
+ features = grouped_gates.keys.map { |key| Flipper::Feature.new(key, self) }
126
139
  features.each do |feature|
127
- result[feature.key] = result_for_feature(feature, grouped_db_gates[feature.key])
140
+ result[feature.key] = result_for_gates(feature, grouped_gates[feature.key])
128
141
  end
129
142
  result
130
143
  end
@@ -219,22 +232,22 @@ module Flipper
219
232
  # already added so no need move on with life
220
233
  end
221
234
 
222
- def result_for_feature(feature, db_gates)
223
- db_gates ||= []
235
+ def result_for_gates(feature, gates)
224
236
  result = {}
237
+ gates ||= []
225
238
  feature.gates.each do |gate|
226
239
  result[gate.key] =
227
240
  case gate.data_type
228
241
  when :boolean
229
- if detected_db_gate = db_gates.detect { |db_gate| db_gate.key == gate.key.to_s }
230
- detected_db_gate.value
242
+ if row = gates.detect { |key, value| !key.nil? && key.to_sym == gate.key }
243
+ row.last
231
244
  end
232
245
  when :integer
233
- if detected_db_gate = db_gates.detect { |db_gate| db_gate.key == gate.key.to_s }
234
- detected_db_gate.value
246
+ if row = gates.detect { |key, value| !key.nil? && key.to_sym == gate.key }
247
+ row.last
235
248
  end
236
249
  when :set
237
- db_gates.select { |db_gate| db_gate.key == gate.key.to_s }.map(&:value).to_set
250
+ gates.select { |key, value| !key.nil? && key.to_sym == gate.key }.map(&:last).to_set
238
251
  else
239
252
  unsupported_data_type gate.data_type
240
253
  end
@@ -1,3 +1,3 @@
1
1
  module Flipper
2
- VERSION = '0.26.1'.freeze
2
+ VERSION = '0.27.0'.freeze
3
3
  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: 0.26.1
4
+ version: 0.27.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: 2023-03-15 00:00:00.000000000 Z
11
+ date: 2023-03-18 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: 0.26.1
19
+ version: 0.27.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: 0.26.1
26
+ version: 0.27.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -51,8 +51,12 @@ executables: []
51
51
  extensions: []
52
52
  extra_rdoc_files: []
53
53
  files:
54
+ - benchmark/active_record_adapter_ips.rb
55
+ - benchmark/active_record_ips.rb
56
+ - benchmark/active_record_setup.rb
54
57
  - examples/active_record/ar_setup.rb
55
58
  - examples/active_record/basic.rb
59
+ - examples/active_record/cached.rb
56
60
  - examples/active_record/internals.rb
57
61
  - flipper-active_record.gemspec
58
62
  - lib/flipper-active_record.rb