diff --git a/Gemfile.lock b/Gemfile.lock index 5ea1b0c..60e53f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -21,12 +21,18 @@ GEM ast (2.4.2) coderay (1.1.3) concurrent-ruby (1.2.2) + debug (1.8.0) + irb (>= 1.5.0) + reline (>= 0.3.1) diff-lcs (1.5.0) docile (1.4.0) faker (3.2.0) i18n (>= 1.8.11, < 2) i18n (1.14.1) concurrent-ruby (~> 1.0) + io-console (0.6.0) + irb (1.7.4) + reline (>= 0.3.6) json (2.6.3) language_server-protocol (3.17.0.3) lint_roller (1.1.0) @@ -45,6 +51,8 @@ GEM rainbow (3.1.1) rake (13.0.6) regexp_parser (2.8.1) + reline (0.3.7) + io-console (~> 0.5) rexml (3.2.5) rspec (3.12.0) rspec-core (~> 3.12.0) @@ -112,6 +120,7 @@ PLATFORMS x86_64-linux DEPENDENCIES + debug (>= 1.0.0) faker (~> 3.2) mysql2 (~> 0.5.5) pg (~> 1.5) diff --git a/bin/setup b/bin/setup index 118fa68..8c45a56 100755 --- a/bin/setup +++ b/bin/setup @@ -9,19 +9,9 @@ set -vx # PostgreSQL if [ -x "$(command -v psql)" ]; then echo "PostgreSQL is installed" - psql -h localhost -p 5432 -W postgres -c 'create database random_rails_test;' -U postgres; -else - echo "PostgreSQL is not installed" - # check it is mac or linux - if [ "$(uname)" == "Darwin" ]; then - brew install postgresql - elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - sudo apt-get install postgresql postgresql-contrib - fi - - # create psql user - sudo -u postgres createuser -s $(whoami) psql -h localhost -p 5432 -W postgres -c 'create database random_rails_test;' -U $(whoami); +else + echo "PostgreSQL is not installed!" exit 1 fi @@ -31,19 +21,12 @@ if [ -x "$(command -v mysql)" ]; then echo "MySQL is installed" mysql -h localhost -P 3306 -u root -e 'create database random_rails_test;' else - echo "MySQL is not installed" - # check it is mac or linux - if [ "$(uname)" == "Darwin" ]; then - brew install gcc zstd openssl mysql - elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - sudo apt-get install mysql-server mysql-client libmysqlclient-dev - fi - - # create mysql user - mysql -h localhost -P 3306 -u root -e 'create database random_rails_test;' + echo "MySQL is not installed!" exit 1 fi +# add sqlite + bundle install DB=pg bundle exec rspec diff --git a/lib/random-rails/adapters/active_record/base.rb b/lib/random-rails/adapters/active_record/base.rb index 8fcae0b..364a157 100644 --- a/lib/random-rails/adapters/active_record/base.rb +++ b/lib/random-rails/adapters/active_record/base.rb @@ -1,12 +1,36 @@ +require "active_record" +require "debug" module RandomRails module Adapters module ActiveRecord module Base def random(precision: 10) # TODO: use different ways to sample data depending on the database adapter - from("#{table_name} TABLESAMPLE BERNOULLI(#{precision})").limit(1) + if connection.adapter_name == "postgresql" + from("#{table_name} TABLESAMPLE BERNOULLI(#{precision})").limit(1) + else + # from("\"#{table_name}\" LIMIT 1 OFFSET (SELECT CAST(ROUND(RANDOM() * (SELECT COUNT(*) FROM \"#{table_name}\"))) AS INTEGER)") + # ================= + # offset_value = connection.select_value("SELECT RANDOM() % MAX(id) FROM \"people\"").abs + + # offset(offset_value).limit(1) + # ================= + # binding.irb + from("\"#{table_name}\" LIMIT 1 OFFSET abs(random() % (SELECT count(*) FROM \"#{table_name}\"))") + + # SELECT "people".* FROM "people" LIMIT 1 OFFSET abs(random()%(SELECT count(*) FROM "people")); + + # from("\"#{table_name}\" OFFSET (SELECT CAST(ROUND(RANDOM() * (SELECT COUNT(*) FROM \"#{table_name}\")) AS INTEGER))") + # people limit 1 offset (SELECT CAST(ROUND(RANDOM() * (SELECT COUNT(*) FROM "people")) AS INTEGER)) + end end end end end end + +# select * from people limit 1 offset (SELECT CAST(ROUND(RANDOM() * (SELECT COUNT(*) FROM "people")) AS INTEGER)) + + + +# SELECT ROUND(RANDOM() * (SELECT COUNT(*) FROM users)) FROM users LIMIT 1 diff --git a/random-rails.gemspec b/random-rails.gemspec index 319e018..d16d27c 100644 --- a/random-rails.gemspec +++ b/random-rails.gemspec @@ -42,6 +42,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rubocop-performance", "~> 1.18" spec.add_development_dependency "simplecov", "~> 0.22.0" spec.add_development_dependency "pry", "~> 0.14.2" + spec.add_development_dependency "debug", ">= 1.0.0" spec.add_development_dependency "sqlite3", "~> 1.6" spec.add_development_dependency "pg", "~> 1.5" spec.add_development_dependency "mysql2", "~> 0.5.5" diff --git a/random_rails_test.sqlite3 b/random_rails_test.sqlite3 new file mode 100644 index 0000000..84c9564 Binary files /dev/null and b/random_rails_test.sqlite3 differ diff --git a/spec/lib/random/adapters/active_record/base_spec.rb b/spec/lib/random/adapters/active_record/base_spec.rb index e4cd560..0dcd324 100644 --- a/spec/lib/random/adapters/active_record/base_spec.rb +++ b/spec/lib/random/adapters/active_record/base_spec.rb @@ -1,13 +1,27 @@ # frozen_string_literal: true - +require "pry" RSpec.describe RandomRails::Adapters::ActiveRecord::Base do describe "#random" do it { expect(Person).to respond_to(:random) } it { expect(Person.random).to be_a(ActiveRecord::Relation) } - it { expect(Person.random.to_sql).to include("TABLESAMPLE BERNOULLI") } + + case ActiveRecord::Base.connection.adapter_name + when "PostgreSQL" + it { expect(Person.random.to_sql).to include("TABLESAMPLE BERNOULLI") } + when "SQLite" + it { expect(Person.random.to_sql).to include("OFFSET") } + end context "when precision is specified" do - it { expect(Person.random(precision: 5).to_sql).to include("TABLESAMPLE BERNOULLI(5)") } + case ActiveRecord::Base.connection.adapter_name + when "PostgreSQL" + it { expect(Person.random(precision: 5).to_sql).to include("TABLESAMPLE BERNOULLI(5)") } + when "SQLite" + it { expect(Person.random(precision: 5).to_sql).to include("OFFSET") } + end + + # the main poblem is that calling `Person.random.inspect` will execute the query with "LIMIT ?" at the end that raises a syntax error + it { binding.irb; expect(Person.random.inspect).to include(ActiveRecord::Relation.to_s) } end context "when limit is specified" do @@ -15,3 +29,28 @@ end end end + + +# Person.from(" +# users +# OFFSET ROUND( +# RAND() * ( +# SELECT COUNT(*) FROM users +# ) +# ) +# ").limit(1).inspect + + +# offset = "SELECT ROUND(RAND() * (SELECT COUNT(*) FROM users))" + +# "SELECT * FROM users OFFSET #{offset}" + + +# # * Correct offset +# # ROUND(RANDOM() * (SELECT COUNT(*) FROM people)) + +# offset = "ROUND(RANDOM() * (SELECT COUNT(*) FROM people))" + +# sql = "SELECT * FROM people OFFSET #{offset}" + +# Person.from("people OFFSET #{offset}") diff --git a/spec/support/schema.rb b/spec/support/schema.rb index 0c2736a..65c3f62 100644 --- a/spec/support/schema.rb +++ b/spec/support/schema.rb @@ -24,7 +24,8 @@ # Otherwise, assume SQLite3: `bundle exec rake spec` ActiveRecord::Base.establish_connection( adapter: "sqlite3", - database: ":memory:" + # database: ":memory:" + database: "random_rails_test.sqlite3" ) end