fino 1.10.0 → 1.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b848e452b4dd15c07680a8e27822e978a35152e8a2fcf24193e61af3bdbc2c55
4
- data.tar.gz: dabde784e2b9c36d9f258b70a9885052f8d567e0ffc21ace004d1441bb219651
3
+ metadata.gz: 677e25b9a4daff0aaf1fa179f2571f954b7afdc495685339c3dbff7183656802
4
+ data.tar.gz: 9ca91a58789efec0a8db42c92aa557de41ce1d6f5c812d71477b32f9d76644fd
5
5
  SHA512:
6
- metadata.gz: 795b2922a6b205ce6e9015f34c69d7cf7b5b501d54cec81968766d6510148d734b1f0c09fd3193646616759b826964aef9def7d7a572e11dbe362ca50f06a6fe
7
- data.tar.gz: 9a85da0390f427490012c41a2eb004bbdb7bdabdf7a2166da450fc7e003d010f9a97baed16ea2f6cdb316a41474703198220ebb2dda0b28bac12cf86d7f96775
6
+ metadata.gz: dfb43f74199a960f91c72d7e234df8e376eb30a7169b596f0985716e5df63dc09a08af2f834b036d359367139fd8675a62de1dd0ff62337608955c8b1c10550a
7
+ data.tar.gz: 55932466337a4bfe50926786810c22f9dc3fe81285f08620699cc5409814ed38651ade65a9caeaae3e6c10d2ecc56cb163f66f2c8cb122343db86f3c677c79e2
data/README.md CHANGED
@@ -238,7 +238,7 @@ Fino.value(:model, at: :openai, for: "user_2") #=> "gpt-5"
238
238
 
239
239
  #### Experiment analysis
240
240
 
241
- Some Fino adapters support A/B testing analysis, e.g built-in Redis adapter
241
+ Fino adapters might support A/B testing analysis, both built-in `solid` and `redis` adapters do
242
242
 
243
243
  When you run an A/B test for a setting, fino automatically calculates variant based on a stable identifier you pass as
244
244
  a `for` option
@@ -416,6 +416,14 @@ end
416
416
  end
417
417
  ```
418
418
 
419
+ ## Development
420
+
421
+ To create and mugrate dummy app db to test solid adapter, do
422
+
423
+ ```bash
424
+ cd spec/dummy && bin/rails db:create db:migrate
425
+ ```
426
+
419
427
  ## Releasing
420
428
 
421
429
  `rake release`
@@ -11,9 +11,8 @@ module Fino::Library::AbTestingAnalysisSupport
11
11
 
12
12
  setting_instance = fetch_ab_testable_setting(setting_name, at: at)
13
13
  variant = setting_instance.experiment.variant(for: scope)
14
- timestamp_ms = (time.to_f * 1000).to_i
15
14
 
16
- adapter.record_ab_testing_conversion(setting_instance.definition, variant, scope, timestamp_ms)
15
+ adapter.record_ab_testing_conversion(setting_instance.definition, variant, scope, time)
17
16
  end
18
17
 
19
18
  def convert(setting_name, at: nil, time: Time.now, **context)
@@ -62,7 +62,7 @@ class Fino::Settings::Select
62
62
  def resolve(path, force: false)
63
63
  string_path = path.compact.map(&:to_s)
64
64
 
65
- return if !force && @options.dig(*string_path)
65
+ return if !force && @options.dig(*string_path).present?
66
66
 
67
67
  builder = @builders.dig(*string_path)
68
68
  options = builder.respond_to?(:call) ? builder.call(refresh: force) : builder
@@ -37,7 +37,7 @@ module Fino
37
37
 
38
38
  Fino::Solid::Setting.upsert(
39
39
  { key: setting_definition.key, data: data },
40
- unique_by: :key
40
+ **unique_by_option(:key)
41
41
  )
42
42
  end
43
43
 
@@ -45,8 +45,8 @@ module Fino
45
45
  Fino::Solid::Setting.pluck(:key)
46
46
  end
47
47
 
48
- def clear(setting_key)
49
- Fino::Solid::Setting.where(key: setting_key).delete_all > 0
48
+ def clear(setting_key) # rubocop:disable Naming/PredicateMethod
49
+ Fino::Solid::Setting.where(key: setting_key).delete_all.positive?
50
50
  end
51
51
 
52
52
  def fetch_value_from(raw_adapter_data)
@@ -62,6 +62,36 @@ module Fino
62
62
  end
63
63
  end
64
64
 
65
+ def record_ab_testing_conversion(setting_definition, variant, scope, time)
66
+ Fino::Solid::Conversion.insert(
67
+ {
68
+ setting_key: setting_definition.key,
69
+ variant_id: variant.id,
70
+ scope: scope.to_s,
71
+ converted_at: time
72
+ },
73
+ **unique_by_option(:idx_fino_conversions_unique)
74
+ )
75
+ end
76
+
77
+ def read_ab_testing_conversions(setting_definition, variants)
78
+ rows =
79
+ Fino::Solid::Conversion
80
+ .where(setting_key: setting_definition.key, variant_id: variants.map(&:id))
81
+ .pluck(:variant_id, :scope, :converted_at)
82
+
83
+ grouped = rows.group_by(&:first)
84
+
85
+ variants.each_with_object({}) do |variant, memo|
86
+ entries = grouped.fetch(variant.id, [])
87
+ memo[variant] = entries.map { |_vid, scope, converted_at| [scope, (converted_at.to_f * 1000).to_i] }
88
+ end
89
+ end
90
+
91
+ def clear_ab_testing_conversions(setting_key)
92
+ Fino::Solid::Conversion.where(setting_key: setting_key).delete_all
93
+ end
94
+
65
95
  def fetch_raw_variants_from(raw_adapter_data)
66
96
  raw_adapter_data.each_with_object([]) do |(key, value), memo|
67
97
  next unless key.start_with?("#{VARIANT_PREFIX}/")
@@ -71,6 +101,18 @@ module Fino
71
101
  memo << { percentage: percentage.to_f, value: value }
72
102
  end
73
103
  end
104
+
105
+ private
106
+
107
+ def unique_by_option(constraint)
108
+ return {} if mysql_adapter?
109
+
110
+ { unique_by: constraint }
111
+ end
112
+
113
+ def mysql_adapter?
114
+ Fino::Solid::Record.connection.adapter_name.match?(/Mysql2|Trilogy/i)
115
+ end
74
116
  end
75
117
  end
76
118
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fino
4
+ module Solid
5
+ class Conversion < Record
6
+ self.table_name = "fino_ab_testing_conversions"
7
+ end
8
+ end
9
+ end
@@ -11,8 +11,10 @@ module Fino
11
11
 
12
12
  source_root File.expand_path("templates", __dir__)
13
13
 
14
- def copy_migration
14
+ def copy_migrations
15
15
  migration_template "create_fino_settings.rb.tt", File.join(db_migrate_path, "create_fino_settings.rb")
16
+ migration_template "create_fino_ab_testing_conversions.rb.tt",
17
+ File.join(db_migrate_path, "create_fino_ab_testing_conversions.rb")
16
18
  end
17
19
 
18
20
  private
data/lib/fino/solid.rb CHANGED
@@ -16,6 +16,7 @@ end
16
16
 
17
17
  require "fino/solid/record"
18
18
  require "fino/solid/setting"
19
+ require "fino/solid/conversion"
19
20
  require "fino/solid/adapter"
20
21
  require "fino/solid/railtie" if defined?(Rails::Railtie)
21
22
 
data/lib/fino/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fino
4
- VERSION = "1.10.0"
4
+ VERSION = "1.11.1"
5
5
  REQUIRED_RUBY_VERSION = ">= 3.2.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fino
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 1.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Egor Iskrenkov
@@ -67,6 +67,7 @@ files:
67
67
  - lib/fino/settings/string.rb
68
68
  - lib/fino/solid.rb
69
69
  - lib/fino/solid/adapter.rb
70
+ - lib/fino/solid/conversion.rb
70
71
  - lib/fino/solid/generators/install/install_generator.rb
71
72
  - lib/fino/solid/railtie.rb
72
73
  - lib/fino/solid/record.rb
@@ -93,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
94
  - !ruby/object:Gem::Version
94
95
  version: '0'
95
96
  requirements: []
96
- rubygems_version: 3.6.9
97
+ rubygems_version: 4.0.6
97
98
  specification_version: 4
98
99
  summary: Plug & play distributed settings engine for Ruby and Rails
99
100
  test_files: []