From 2b93aa58fb5de58cc0922a2a9b1accc628c85664 Mon Sep 17 00:00:00 2001 From: Egor Iskrenkov Date: Tue, 24 Mar 2026 01:25:23 +0100 Subject: [PATCH 1/9] Run CI against multiple DB adapters --- .github/workflows/rspec.yml | 71 ++++++++++++++++++- fino-solid.gemspec | 1 + lib/fino/solid/adapter.rb | 16 ++++- .../adapters/solid_adapter_spec.rb | 16 ++++- spec/support/solid_test_helpers.rb | 8 +++ 5 files changed, 106 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index d986903..ec2bda6 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ["3.2", "3.3", "3.4", "4.0"] + ruby-version: ["3.2", "3.3", "3.4"] services: redis: @@ -38,3 +38,72 @@ jobs: bundler-cache: true - run: bundle exec rspec + + adapters: + name: "Ruby 4.0 / ${{ matrix.adapter }}" + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + adapter: [redis, sqlite3, postgresql, mysql2, trilogy] + + services: + redis: + image: redis:7 + ports: + - 6379:6379 + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + postgres: + image: postgres:17 + ports: + - 5432:5432 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: fino_test + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + mysql: + image: mysql:8.4 + ports: + - 3306:3306 + env: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: fino_test + options: >- + --health-cmd "mysqladmin ping -h 127.0.0.1" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + env: + FINO_TEST_REDIS_HOST: localhost + FINO_TEST_ADAPTER: ${{ matrix.adapter }} + FINO_TEST_POSTGRES_HOST: localhost + FINO_TEST_POSTGRES_USER: postgres + FINO_TEST_POSTGRES_PASSWORD: postgres + FINO_TEST_POSTGRES_DB: fino_test + FINO_TEST_MYSQL_HOST: 127.0.0.1 + FINO_TEST_MYSQL_USER: root + FINO_TEST_MYSQL_PASSWORD: root + FINO_TEST_MYSQL_DB: fino_test + + steps: + - uses: actions/checkout@v4 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "4.0" + bundler-cache: true + + - run: bundle exec rspec diff --git a/fino-solid.gemspec b/fino-solid.gemspec index 2a62a0b..2199382 100644 --- a/fino-solid.gemspec +++ b/fino-solid.gemspec @@ -34,4 +34,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency "mysql2", ">= 0.5" spec.add_development_dependency "pg", ">= 1.0" spec.add_development_dependency "sqlite3", ">= 1.4" + spec.add_development_dependency "trilogy", ">= 2.0" end diff --git a/lib/fino/solid/adapter.rb b/lib/fino/solid/adapter.rb index ad15d6d..877dd85 100644 --- a/lib/fino/solid/adapter.rb +++ b/lib/fino/solid/adapter.rb @@ -37,7 +37,7 @@ def write(setting_definition, value, overrides, variants) Fino::Solid::Setting.upsert( { key: setting_definition.key, data: data }, - unique_by: :key + **unique_by_option(:key) ) end @@ -70,7 +70,7 @@ def record_ab_testing_conversion(setting_definition, variant, scope, time) scope: scope.to_s, converted_at: time }, - unique_by: :idx_fino_conversions_unique + **unique_by_option(:idx_fino_conversions_unique) ) end @@ -101,6 +101,18 @@ def fetch_raw_variants_from(raw_adapter_data) memo << { percentage: percentage.to_f, value: value } end end + + private + + def unique_by_option(constraint) + return {} if mysql_adapter? + + { unique_by: constraint } + end + + def mysql_adapter? + Fino::Solid::Record.connection.adapter_name.match?(/Mysql2|Trilogy/i) + end end end end diff --git a/spec/integration/adapters/solid_adapter_spec.rb b/spec/integration/adapters/solid_adapter_spec.rb index cad1568..3d2bbfd 100644 --- a/spec/integration/adapters/solid_adapter_spec.rb +++ b/spec/integration/adapters/solid_adapter_spec.rb @@ -3,11 +3,21 @@ require "spec_helper" RSpec.describe "Solid adapter integration", type: :integration do + adapter_name = ENV.fetch("FINO_TEST_ADAPTER", "sqlite3") + before(:all) do - SolidTestHelpers.setup_database(:sqlite3) + skip "Solid adapter not under test" if adapter_name == "redis" + + begin + SolidTestHelpers.setup_database(adapter_name.to_sym) + rescue => e + raise if ENV["CI"] + + skip "#{adapter_name} not available: #{e.message}" + end Fino.reconfigure do - adapter { SolidTestHelpers.solid_adapter } + adapter { Fino::Solid::Adapter.new } cache { TestHelpers.cache } settings do @@ -47,7 +57,7 @@ describe "#supports_ab_testing_analysis?" do it "returns true" do - expect(SolidTestHelpers.solid_adapter.supports_ab_testing_analysis?).to eq(true) + expect(Fino::Solid::Adapter.new.supports_ab_testing_analysis?).to eq(true) end end end diff --git a/spec/support/solid_test_helpers.rb b/spec/support/solid_test_helpers.rb index 499ae7e..99fbb43 100644 --- a/spec/support/solid_test_helpers.rb +++ b/spec/support/solid_test_helpers.rb @@ -31,6 +31,14 @@ def database_config(adapter_name) username: ENV.fetch("FINO_TEST_POSTGRES_USER", "postgres"), password: ENV.fetch("FINO_TEST_POSTGRES_PASSWORD", "") } + when :trilogy + { + adapter: "trilogy", + host: ENV.fetch("FINO_TEST_MYSQL_HOST", "mysql.fino.orb.local"), + database: ENV.fetch("FINO_TEST_MYSQL_DB", "fino_test"), + username: ENV.fetch("FINO_TEST_MYSQL_USER", "root"), + password: ENV.fetch("FINO_TEST_MYSQL_PASSWORD", "") + } when :mysql2 { adapter: "mysql2", From 3f902be2b24e2cfe0a2b38d8f31011ee5f81385c Mon Sep 17 00:00:00 2001 From: Egor Iskrenkov Date: Mon, 30 Mar 2026 10:55:03 +0200 Subject: [PATCH 2/9] should fail --- lib/fino/solid/adapter.rb | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/fino/solid/adapter.rb b/lib/fino/solid/adapter.rb index 877dd85..9e0782a 100644 --- a/lib/fino/solid/adapter.rb +++ b/lib/fino/solid/adapter.rb @@ -70,7 +70,7 @@ def record_ab_testing_conversion(setting_definition, variant, scope, time) scope: scope.to_s, converted_at: time }, - **unique_by_option(:idx_fino_conversions_unique) + unique_by: :idx_fino_conversions_unique ) end @@ -101,18 +101,6 @@ def fetch_raw_variants_from(raw_adapter_data) memo << { percentage: percentage.to_f, value: value } end end - - private - - def unique_by_option(constraint) - return {} if mysql_adapter? - - { unique_by: constraint } - end - - def mysql_adapter? - Fino::Solid::Record.connection.adapter_name.match?(/Mysql2|Trilogy/i) - end end end end From dc8d183c0b14662b7687d9a4b9f76036975d78a2 Mon Sep 17 00:00:00 2001 From: Egor Iskrenkov Date: Mon, 30 Mar 2026 12:31:13 +0200 Subject: [PATCH 3/9] more matrix entries --- .github/workflows/rspec.yml | 158 ++++++++++-------- Gemfile | 9 +- fino-solid.gemspec | 5 - lib/fino/solid/adapter.rb | 2 +- .../adapters/redis_adapter_spec.rb | 2 + .../adapters/solid_adapter_spec.rb | 17 +- spec/support/from_scratch.rb | 14 +- spec/support/test_helpers.rb | 25 ++- 8 files changed, 132 insertions(+), 100 deletions(-) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index ec2bda6..f9ba604 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -8,87 +8,57 @@ on: jobs: test: + name: "Ruby ${{ matrix.ruby-version }} / ${{ matrix.adapter-name }}${{ matrix.adapter_version && format(' {0}', matrix.adapter_version) || '' }}" runs-on: ubuntu-latest strategy: fail-fast: false matrix: - ruby-version: ["3.2", "3.3", "3.4"] - - services: - redis: - image: redis:7 - ports: - - 6379:6379 - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 + include: + - ruby-version: "3.2" + adapter: redis + adapter-name: Redis + - ruby-version: "3.2" + adapter: solid/sqlite3 + adapter-name: SQLite + - ruby-version: "3.3" + adapter: redis + adapter-name: Redis + - ruby-version: "3.3" + adapter: solid/sqlite3 + adapter-name: SQLite + - ruby-version: "3.4" + adapter: redis + adapter-name: Redis + - ruby-version: "3.4" + adapter: solid/sqlite3 + adapter-name: SQLite + - ruby-version: "3.4" + adapter: solid/sqlite3 + adapter-name: SQLite + adapter_version: "1.7" + rails-version: "7.2" + + # Run tests against all adapters for latest Ruby version + - ruby-version: "4.0" + adapter: redis + adapter-name: Redis + - ruby-version: "4.0" + adapter: solid/sqlite3 + adapter-name: SQLite + - ruby-version: "4.0" + adapter: solid/postgresql + adapter-name: PostgreSQL + - ruby-version: "4.0" + adapter: solid/mysql2 + adapter-name: MySQL (mysql2) + - ruby-version: "4.0" + adapter: solid/trilogy + adapter-name: "MySQL (trilogy)" env: - FINO_TEST_REDIS_HOST: localhost - - steps: - - uses: actions/checkout@v4 - - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby-version }} - bundler-cache: true - - - run: bundle exec rspec - - adapters: - name: "Ruby 4.0 / ${{ matrix.adapter }}" - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - adapter: [redis, sqlite3, postgresql, mysql2, trilogy] - - services: - redis: - image: redis:7 - ports: - - 6379:6379 - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - postgres: - image: postgres:17 - ports: - - 5432:5432 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: fino_test - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - mysql: - image: mysql:8.4 - ports: - - 3306:3306 - env: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: fino_test - options: >- - --health-cmd "mysqladmin ping -h 127.0.0.1" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - env: - FINO_TEST_REDIS_HOST: localhost FINO_TEST_ADAPTER: ${{ matrix.adapter }} + FINO_TEST_REDIS_HOST: localhost FINO_TEST_POSTGRES_HOST: localhost FINO_TEST_POSTGRES_USER: postgres FINO_TEST_POSTGRES_PASSWORD: postgres @@ -101,9 +71,49 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Set adapter version override + if: matrix.adapter_version + run: | + GEM_NAME="${FINO_TEST_ADAPTER#solid/}" + ENV_NAME="$(echo "${GEM_NAME}" | tr '[:lower:]' '[:upper:]')_VERSION" + echo "${ENV_NAME}=${{ matrix.adapter_version }}" >> $GITHUB_ENV + + - name: Set Rails version override + if: matrix.rails-version + run: echo "RAILS_VERSION=${{ matrix.rails-version }}" >> $GITHUB_ENV + + - name: Clear lockfile for version overrides + if: matrix.adapter_version || matrix.rails-version + run: rm Gemfile.lock + + - name: Start Redis + if: matrix.adapter == 'redis' + run: | + docker run -d --name redis -p 6379:6379 redis:7 + timeout 30 bash -c 'until docker exec redis redis-cli ping 2>/dev/null; do sleep 1; done' + + - name: Start PostgreSQL + if: matrix.adapter == 'solid/postgresql' + run: | + docker run -d --name postgres -p 5432:5432 \ + -e POSTGRES_USER=postgres \ + -e POSTGRES_PASSWORD=postgres \ + -e POSTGRES_DB=fino_test \ + postgres:17 + timeout 30 bash -c 'until docker exec postgres pg_isready 2>/dev/null; do sleep 1; done' + + - name: Start MySQL + if: matrix.adapter == 'solid/mysql2' || matrix.adapter == 'solid/trilogy' + run: | + docker run -d --name mysql -p 3306:3306 \ + -e MYSQL_ROOT_PASSWORD=root \ + -e MYSQL_DATABASE=fino_test \ + mysql:8.4 + timeout 60 bash -c 'until docker exec mysql mysqladmin ping -h 127.0.0.1 --silent 2>/dev/null; do sleep 1; done' + - uses: ruby/setup-ruby@v1 with: - ruby-version: "4.0" + ruby-version: ${{ matrix.ruby-version }} bundler-cache: true - run: bundle exec rspec diff --git a/Gemfile b/Gemfile index 505f186..2a90412 100644 --- a/Gemfile +++ b/Gemfile @@ -16,8 +16,13 @@ gem "guard-livereload" gem "rack-livereload" gem "puma" -gem "rails", "~> #{ENV['RAILS_VERSION'] || '8.0'}" -gem "sqlite3", "~> #{ENV['SQLITE_VERSION'] || '2.7'}" +gem "rails", "~> #{ENV.fetch('RAILS_VERSION', '8.0')}" + +# Database adapters +gem "mysql2", "~> #{ENV.fetch('MYSQL2_VERSION', '0')}" +gem "pg", "~> #{ENV.fetch('POSTGRESQL_VERSION', '1')}" +gem "sqlite3", "~> #{ENV.fetch('SQLITE3_VERSION', '2')}" +gem "trilogy", "~> #{ENV.fetch('TRILOGY_VERSION', '2')}" gem "rspec", "~> 3.0" gem "rubocop", "~> 1.80.1", require: false diff --git a/fino-solid.gemspec b/fino-solid.gemspec index 2199382..d3daf4f 100644 --- a/fino-solid.gemspec +++ b/fino-solid.gemspec @@ -30,9 +30,4 @@ Gem::Specification.new do |spec| spec.add_dependency "activerecord", ">= 6.1" spec.add_dependency "fino", "~> #{Fino::VERSION}" - - spec.add_development_dependency "mysql2", ">= 0.5" - spec.add_development_dependency "pg", ">= 1.0" - spec.add_development_dependency "sqlite3", ">= 1.4" - spec.add_development_dependency "trilogy", ">= 2.0" end diff --git a/lib/fino/solid/adapter.rb b/lib/fino/solid/adapter.rb index 9e0782a..ad15d6d 100644 --- a/lib/fino/solid/adapter.rb +++ b/lib/fino/solid/adapter.rb @@ -37,7 +37,7 @@ def write(setting_definition, value, overrides, variants) Fino::Solid::Setting.upsert( { key: setting_definition.key, data: data }, - **unique_by_option(:key) + unique_by: :key ) end diff --git a/spec/integration/adapters/redis_adapter_spec.rb b/spec/integration/adapters/redis_adapter_spec.rb index 5608838..2666116 100644 --- a/spec/integration/adapters/redis_adapter_spec.rb +++ b/spec/integration/adapters/redis_adapter_spec.rb @@ -4,6 +4,8 @@ RSpec.describe "Redis adapter integration", type: :integration do before(:all) do + skip "Redis adapter not under test" unless TestHelpers.redis_adapter? + Fino.reconfigure do adapter { TestHelpers.adapter } cache { TestHelpers.cache } diff --git a/spec/integration/adapters/solid_adapter_spec.rb b/spec/integration/adapters/solid_adapter_spec.rb index 3d2bbfd..1da31be 100644 --- a/spec/integration/adapters/solid_adapter_spec.rb +++ b/spec/integration/adapters/solid_adapter_spec.rb @@ -3,18 +3,8 @@ require "spec_helper" RSpec.describe "Solid adapter integration", type: :integration do - adapter_name = ENV.fetch("FINO_TEST_ADAPTER", "sqlite3") - before(:all) do - skip "Solid adapter not under test" if adapter_name == "redis" - - begin - SolidTestHelpers.setup_database(adapter_name.to_sym) - rescue => e - raise if ENV["CI"] - - skip "#{adapter_name} not available: #{e.message}" - end + skip "Solid adapter not under test" unless TestHelpers.solid_adapter? Fino.reconfigure do adapter { Fino::Solid::Adapter.new } @@ -48,11 +38,6 @@ end end - before do - TestHelpers.cache.clear - SolidTestHelpers.clear_database - end - it_behaves_like "fino adapter integration" describe "#supports_ab_testing_analysis?" do diff --git a/spec/support/from_scratch.rb b/spec/support/from_scratch.rb index 2309828..c331d2f 100644 --- a/spec/support/from_scratch.rb +++ b/spec/support/from_scratch.rb @@ -1,8 +1,20 @@ # frozen_string_literal: true RSpec.configure do |config| + config.before(:suite) do + next unless TestHelpers.solid_adapter? + + db_adapter = TestHelpers.adapter_env.delete_prefix("solid/").to_sym + SolidTestHelpers.setup_database(db_adapter) + end + config.before do TestHelpers.cache.clear - TestHelpers.redis.flushdb + + if TestHelpers.solid_adapter? + SolidTestHelpers.clear_database + else + TestHelpers.redis.flushdb + end end end diff --git a/spec/support/test_helpers.rb b/spec/support/test_helpers.rb index c52d6c3..cbead89 100644 --- a/spec/support/test_helpers.rb +++ b/spec/support/test_helpers.rb @@ -1,8 +1,27 @@ # frozen_string_literal: true module TestHelpers + VALID_ADAPTERS = %w[redis solid/sqlite3 solid/postgresql solid/mysql2 solid/trilogy].freeze + DEFAULT_ADAPTER = "redis" + module_function + def adapter_env + @adapter_env ||= ENV.fetch("FINO_TEST_ADAPTER", DEFAULT_ADAPTER).tap do |value| + unless VALID_ADAPTERS.include?(value) + raise "Unknown test adapter: #{value}. Valid: #{VALID_ADAPTERS.join(', ')}" + end + end + end + + def redis_adapter? + adapter_env == "redis" + end + + def solid_adapter? + adapter_env.start_with?("solid/") + end + def cache @cache ||= Fino::Cache::Memory.new(expires_in: 10) end @@ -15,6 +34,10 @@ def redis end def adapter - @adapter ||= Fino::Redis::Adapter.new(redis, namespace: "fino_test") + @adapter ||= if redis_adapter? + Fino::Redis::Adapter.new(redis, namespace: "fino_test") + elsif solid_adapter? + Fino::Solid::Adapter.new + end end end From 2a86d4fd594a8f536d4b955cd3bd25bf43c90825 Mon Sep 17 00:00:00 2001 From: Egor Iskrenkov Date: Mon, 30 Mar 2026 12:33:35 +0200 Subject: [PATCH 4/9] fix --- .github/workflows/rspec.yml | 4 ---- spec/dummy/.gitignore | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index f9ba604..c52711f 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -82,10 +82,6 @@ jobs: if: matrix.rails-version run: echo "RAILS_VERSION=${{ matrix.rails-version }}" >> $GITHUB_ENV - - name: Clear lockfile for version overrides - if: matrix.adapter_version || matrix.rails-version - run: rm Gemfile.lock - - name: Start Redis if: matrix.adapter == 'redis' run: | diff --git a/spec/dummy/.gitignore b/spec/dummy/.gitignore index 3e5ce68..305ce81 100644 --- a/spec/dummy/.gitignore +++ b/spec/dummy/.gitignore @@ -6,3 +6,5 @@ /storage/* !/storage/.keep + +Gemfile.lock From ed2afba7a80de1ab8ed0c85f7885610183300ce7 Mon Sep 17 00:00:00 2001 From: Egor Iskrenkov Date: Mon, 30 Mar 2026 12:39:58 +0200 Subject: [PATCH 5/9] fix --- .github/workflows/rspec.yml | 15 +++++++-------- lib/fino/solid/adapter.rb | 20 +++++++------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index c52711f..c3bee7e 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -8,7 +8,7 @@ on: jobs: test: - name: "Ruby ${{ matrix.ruby-version }} / ${{ matrix.adapter-name }}${{ matrix.adapter_version && format(' {0}', matrix.adapter_version) || '' }}" + name: "Ruby ${{ matrix.ruby-version }} / ${{ matrix.adapter-name }}${{ matrix.adapter-version && format(' {0}', matrix.adapter-version) || '' }}" runs-on: ubuntu-latest strategy: @@ -33,11 +33,6 @@ jobs: - ruby-version: "3.4" adapter: solid/sqlite3 adapter-name: SQLite - - ruby-version: "3.4" - adapter: solid/sqlite3 - adapter-name: SQLite - adapter_version: "1.7" - rails-version: "7.2" # Run tests against all adapters for latest Ruby version - ruby-version: "4.0" @@ -46,6 +41,10 @@ jobs: - ruby-version: "4.0" adapter: solid/sqlite3 adapter-name: SQLite + - ruby-version: "4.0" + adapter: solid/sqlite3 + adapter-name: SQLite + adapter-version: "1.7" - ruby-version: "4.0" adapter: solid/postgresql adapter-name: PostgreSQL @@ -72,11 +71,11 @@ jobs: - uses: actions/checkout@v4 - name: Set adapter version override - if: matrix.adapter_version + if: matrix.adapter-version run: | GEM_NAME="${FINO_TEST_ADAPTER#solid/}" ENV_NAME="$(echo "${GEM_NAME}" | tr '[:lower:]' '[:upper:]')_VERSION" - echo "${ENV_NAME}=${{ matrix.adapter_version }}" >> $GITHUB_ENV + echo "${ENV_NAME}=${{ matrix.adapter-version }}" >> $GITHUB_ENV - name: Set Rails version override if: matrix.rails-version diff --git a/lib/fino/solid/adapter.rb b/lib/fino/solid/adapter.rb index ad15d6d..401343a 100644 --- a/lib/fino/solid/adapter.rb +++ b/lib/fino/solid/adapter.rb @@ -35,18 +35,15 @@ def write(setting_definition, value, overrides, variants) data["#{VARIANT_PREFIX}/#{variant.percentage}/#{VALUE_KEY}"] = serialize_value.call(variant.value) end - Fino::Solid::Setting.upsert( - { key: setting_definition.key, data: data }, - unique_by: :key - ) + Fino::Solid::Setting.upsert(key: setting_definition.key, data: data) end def read_persisted_setting_keys Fino::Solid::Setting.pluck(:key) end - def clear(setting_key) - Fino::Solid::Setting.where(key: setting_key).delete_all > 0 + def clear(setting_key) # rubocop:disable Naming/PredicateMethod + Fino::Solid::Setting.where(key: setting_key).delete_all.positive? end def fetch_value_from(raw_adapter_data) @@ -64,13 +61,10 @@ def fetch_raw_overrides_from(raw_adapter_data) def record_ab_testing_conversion(setting_definition, variant, scope, time) Fino::Solid::Conversion.insert( - { - setting_key: setting_definition.key, - variant_id: variant.id, - scope: scope.to_s, - converted_at: time - }, - unique_by: :idx_fino_conversions_unique + setting_key: setting_definition.key, + variant_id: variant.id, + scope: scope.to_s, + converted_at: time ) end From 2dec659768f5e9a2ea6824b1e14aa103b1e245a2 Mon Sep 17 00:00:00 2001 From: Egor Iskrenkov Date: Mon, 30 Mar 2026 12:41:27 +0200 Subject: [PATCH 6/9] fix --- lib/fino/solid/adapter.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/fino/solid/adapter.rb b/lib/fino/solid/adapter.rb index 401343a..2ddc807 100644 --- a/lib/fino/solid/adapter.rb +++ b/lib/fino/solid/adapter.rb @@ -35,7 +35,7 @@ def write(setting_definition, value, overrides, variants) data["#{VARIANT_PREFIX}/#{variant.percentage}/#{VALUE_KEY}"] = serialize_value.call(variant.value) end - Fino::Solid::Setting.upsert(key: setting_definition.key, data: data) + Fino::Solid::Setting.upsert({ key: setting_definition.key, data: data }) end def read_persisted_setting_keys @@ -61,10 +61,12 @@ def fetch_raw_overrides_from(raw_adapter_data) def record_ab_testing_conversion(setting_definition, variant, scope, time) Fino::Solid::Conversion.insert( - setting_key: setting_definition.key, - variant_id: variant.id, - scope: scope.to_s, - converted_at: time + { + setting_key: setting_definition.key, + variant_id: variant.id, + scope: scope.to_s, + converted_at: time + } ) end From 23eb26ba56bf718c7d9fdbf2b7221c1ad914e43a Mon Sep 17 00:00:00 2001 From: Egor Iskrenkov Date: Mon, 30 Mar 2026 12:56:48 +0200 Subject: [PATCH 7/9] fix --- lib/fino/solid/adapter.rb | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/fino/solid/adapter.rb b/lib/fino/solid/adapter.rb index 2ddc807..4ad22f9 100644 --- a/lib/fino/solid/adapter.rb +++ b/lib/fino/solid/adapter.rb @@ -35,7 +35,10 @@ def write(setting_definition, value, overrides, variants) data["#{VARIANT_PREFIX}/#{variant.percentage}/#{VALUE_KEY}"] = serialize_value.call(variant.value) end - Fino::Solid::Setting.upsert({ key: setting_definition.key, data: data }) + Fino::Solid::Setting.upsert( + { key: setting_definition.key, data: data }, + **unique_by_option(:key) + ) end def read_persisted_setting_keys @@ -66,7 +69,8 @@ def record_ab_testing_conversion(setting_definition, variant, scope, time) variant_id: variant.id, scope: scope.to_s, converted_at: time - } + }, + **unique_by_option(:idx_fino_conversions_unique) ) end @@ -97,6 +101,18 @@ def fetch_raw_variants_from(raw_adapter_data) memo << { percentage: percentage.to_f, value: value } end end + + private + + def unique_by_option(constraint) + return {} if mysql_adapter? + + { unique_by: constraint } + end + + def mysql_adapter? + Fino::Solid::Record.connection.adapter_name.match?(/Mysql2|Trilogy/i) + end end end end From e3990101a1a73237c81a9a8867561227a901cc91 Mon Sep 17 00:00:00 2001 From: Egor Iskrenkov Date: Sat, 4 Apr 2026 13:45:31 +0200 Subject: [PATCH 8/9] rails 7 for sqlite 1.7 test --- .github/workflows/rspec.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index c3bee7e..b719a01 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -45,6 +45,7 @@ jobs: adapter: solid/sqlite3 adapter-name: SQLite adapter-version: "1.7" + rails-version: "7" - ruby-version: "4.0" adapter: solid/postgresql adapter-name: PostgreSQL From 895ef21c95be3c27c3c3d8d641ebeaeda39a5b50 Mon Sep 17 00:00:00 2001 From: Egor Iskrenkov Date: Sat, 4 Apr 2026 14:11:45 +0200 Subject: [PATCH 9/9] rails 7 --- .github/workflows/rspec.yml | 20 ++++++++++++++++++-- fino-rails.gemspec | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index b719a01..3d75f24 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -8,7 +8,7 @@ on: jobs: test: - name: "Ruby ${{ matrix.ruby-version }} / ${{ matrix.adapter-name }}${{ matrix.adapter-version && format(' {0}', matrix.adapter-version) || '' }}" + name: "Ruby ${{ matrix.ruby-version }}${{ matrix.rails-version && format(' / Rails {0}', matrix.rails-version) || '' }} / ${{ matrix.adapter-name }}${{ matrix.adapter-version && format(' {0}', matrix.adapter-version) || '' }}" runs-on: ubuntu-latest strategy: @@ -34,10 +34,14 @@ jobs: adapter: solid/sqlite3 adapter-name: SQLite - # Run tests against all adapters for latest Ruby version + # Run tests against all adapters and 2 latest rails majors for latest Ruby version - ruby-version: "4.0" adapter: redis adapter-name: Redis + - ruby-version: "4.0" + adapter: redis + adapter-name: Redis + rails-version: "7" - ruby-version: "4.0" adapter: solid/sqlite3 adapter-name: SQLite @@ -49,12 +53,24 @@ jobs: - ruby-version: "4.0" adapter: solid/postgresql adapter-name: PostgreSQL + - ruby-version: "4.0" + adapter: solid/postgresql + adapter-name: PostgreSQL + rails-version: "7" - ruby-version: "4.0" adapter: solid/mysql2 adapter-name: MySQL (mysql2) + - ruby-version: "4.0" + adapter: solid/mysql2 + adapter-name: MySQL (mysql2) + rails-version: "7" - ruby-version: "4.0" adapter: solid/trilogy adapter-name: "MySQL (trilogy)" + - ruby-version: "4.0" + adapter: solid/trilogy + adapter-name: "MySQL (trilogy)" + rails-version: "7" env: FINO_TEST_ADAPTER: ${{ matrix.adapter }} diff --git a/fino-rails.gemspec b/fino-rails.gemspec index 55e9ba5..517d51f 100644 --- a/fino-rails.gemspec +++ b/fino-rails.gemspec @@ -29,5 +29,5 @@ Gem::Specification.new do |spec| ] spec.add_dependency "fino", "~> #{Fino::VERSION}" - spec.add_dependency "rails", "~> 8.0" + spec.add_dependency "rails", ">= 7.0" end