active_record_union 1.2.0 → 1.4.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
- SHA1:
3
- metadata.gz: dc119e16853585b8595e9c7cf0de7b1282f30411
4
- data.tar.gz: eea98a19c016f681636e982ffffb9180e3876e4c
2
+ SHA256:
3
+ metadata.gz: b321a0fac09cf1cc331b5526f907b8dd78844796ed473093396dc08297997415
4
+ data.tar.gz: 020d7aca83f28ecfbf9455c48049f70c7fa0389ec72904c743fd724fd314ad05
5
5
  SHA512:
6
- metadata.gz: efa7fa3f32874d1052bf39f54b4e80e9135980bee70604bf18d12759ba42a5a8ca653427d78ea4ebb9ac6081654a91488ee6758c443d80f7e454061576b7d9f5
7
- data.tar.gz: db0f08034881ebe394d656b3b6f997719aaff48dcc979602ca68d8202454182583d50761e725de811bc35e23b5fcf66286947d868bcf1d14dbb103b22ca0ea65
6
+ metadata.gz: 35cb47fc2d57a16a74dbad2995cd90b87eecdea1a5aca340d8543cb504b73cd2a9cbbdb0e0c6cc4b71b416fcc04f3aa884f588067c316a0cc03dd60e9b5b376d
7
+ data.tar.gz: d0dff7b05b27f31b82d00ffe2f8cb5537b5c91a345ec31b02015cb31d020ace156277f8a9f6a8bac3c326f3890f5202213c909ec94435aac46a8be7a169b0ba9
@@ -0,0 +1,70 @@
1
+ name: RSpec Test Matrix
2
+ on:
3
+ push:
4
+ pull_request:
5
+
6
+ jobs:
7
+ test:
8
+ runs-on: ubuntu-latest
9
+
10
+ services:
11
+ postgresql:
12
+ image: postgres
13
+ ports:
14
+ - 5432:5432
15
+ options: >-
16
+ --health-cmd pg_isready
17
+ --health-interval 10s
18
+ --health-timeout 5s
19
+ --health-retries 5
20
+ env:
21
+ POSTGRES_DB: active_record_union
22
+ POSTGRES_USER: active_record_union
23
+ POSTGRES_PASSWORD: active_record_union
24
+
25
+ mysql2:
26
+ image: mysql:8.0
27
+ env:
28
+ MYSQL_DATABASE: active_record_union
29
+ MYSQL_ROOT_PASSWORD: active_record_union
30
+ options: >-
31
+ --health-cmd "mysqladmin ping"
32
+ --health-interval 10s
33
+ --health-timeout 5s
34
+ ports:
35
+ - "3306:3306"
36
+
37
+ strategy:
38
+ fail-fast: false
39
+ matrix:
40
+ # just define specific versions for each rails version
41
+ include:
42
+ - ruby: 2.6
43
+ rails: "6.0"
44
+ - ruby: "3.0"
45
+ rails: 6.1
46
+ - ruby: 3.1
47
+ rails: "7.0"
48
+ - ruby: 3.2
49
+ rails: 7.1
50
+ - ruby: 3.2
51
+ rails: 7.2
52
+ - ruby: 3.3
53
+ rails: "8.0"
54
+
55
+ env:
56
+ BUNDLE_GEMFILE: "rails_${{ matrix.rails }}.gemfile"
57
+ DB_HOST: 127.0.0.1
58
+ MYSQL_ROOT_HOST: "%"
59
+ MYSQL_DB: active_record_union
60
+ MYSQL_USER: root
61
+ MYSQL_PASSWORD: active_record_union
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+
65
+ - uses: ruby/setup-ruby@v1
66
+ with:
67
+ ruby-version: ${{ matrix.ruby }}
68
+ bundler-cache: true # install gems and cache
69
+
70
+ - run: bundle exec rspec --force-color --format d
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # this is just a convenience for out of the box development
2
+ source 'https://rubygems.org'
3
+
4
+ eval_gemfile File.expand_path('./rails_8.0.gemfile', __dir__)
data/README.md CHANGED
@@ -17,6 +17,10 @@ user_1.posts.union(user_2.posts).union(Post.published)
17
17
  user_1.posts.union_all(user_2.posts)
18
18
  ```
19
19
 
20
+ ActiveRecordUnion is tested against Rails 6.0, 6.1, 7.0, 7.1, 7.2 and 8.0.
21
+
22
+ If you are using Postgres, you might alternatively check out [ActiveRecordExtended](https://github.com/georgekaraszi/ActiveRecordExtended) which includes support for unions as well as other goodies.
23
+
20
24
  ## Installation
21
25
 
22
26
  Add this line to your application's Gemfile:
@@ -127,7 +131,7 @@ SELECT "posts".* FROM (
127
131
 
128
132
  There's a couple things to be aware of when using ActiveRecordUnion:
129
133
 
130
- 1. ActiveRecordUnion with raise an error if you try to UNION any relations that do any preloading/eager-loading. There's no sensible way to do the preloading in the subselects. If enough people complain maybe we can change ActiveRecordUnion to let the queries run anyway but without preloading any records.
134
+ 1. ActiveRecordUnion will raise an error if you try to UNION any relations that do any preloading/eager-loading. There's no sensible way to do the preloading in the subselects. If enough people complain, maybe, we can change ActiveRecordUnion to let the queries run anyway but without preloading any records.
131
135
  2. There's no easy way to get SQLite to allow ORDER BY in the UNION subselects. If you get a syntax error, you can either write `my_relation.reorder(nil).union(other.reorder(nil))` or switch to Postgres.
132
136
 
133
137
  ## Another nifty way to reduce extra queries
@@ -184,6 +188,12 @@ This is a gem not a Rails pull request because the standard of code quality for
184
188
 
185
189
  ## Changelog
186
190
 
191
+ **1.4.0** - October 1, 2025
192
+ - Ready for Rails 8.0! Support for Rails < 6 dropped. Updates provided by [@timdiggins](https://github.com/frederikspang) and [@frederikspang](https://github.com/frederikspang).
193
+
194
+ **1.3.0** - January 14, 2018
195
+ - Ready for Rails 5.2! Updates provided by [@glebm](https://github.com/glebm).
196
+
187
197
  **1.2.0** - June 26, 2016
188
198
  - Ready for Rails 5.0! Updates provided by [@glebm](https://github.com/glebm).
189
199
 
@@ -209,9 +219,9 @@ This public domain dedication follows the the CC0 1.0 at https://creativecommons
209
219
  2. Create your feature branch (`git checkout -b my-new-feature`)
210
220
  3. Run the tests:
211
221
  1. Install MySQL and PostgreSQL.
212
- 2. You may need to create a `test_active_record_union` database on each under the default user.
213
- 3. Run `rake` to test with all supported Rails versions.
214
- 4. Run `rake test_rails_4_2` or `rake test_rails_5_0` to test a specific Rails version.
222
+ 2. You need to be able to connect to a local MySQL and Postgres database as the default user, so the specs can create a `test_active_record_union` database. To set up the users this test expects, execute `bin/create-db-users` (or set the environment variables referenced in `spec/support/databases.rb`).
223
+ 3. Run `rake` to test with all supported Rails versions. All needed dependencies will be installed via Bundler (`gem install bundler` if you happen not to have Bundler yet).
224
+ 4. Run `rake test_rails_8_0` or `rake test_rails_7_2` etc. to test a specific Rails version.
215
225
  4. There is also a `bin/console` command to load up a REPL for playing around
216
226
  5. Commit your changes (`git commit -am 'Add some feature'`)
217
227
  6. Push to the branch (`git push origin my-new-feature`)
data/Rakefile CHANGED
@@ -51,11 +51,11 @@ end
51
51
 
52
52
 
53
53
  TestTasks.gemfiles.each do |gemfile|
54
- rails_version_underscored = gemfile[/rails_(.+)\.gemfile/, 1]
54
+ rails_version = gemfile[/rails_(.+)\.gemfile/, 1]
55
55
 
56
- desc "Test Rails #{rails_version_underscored.gsub("_", ".")}"
57
- task :"test_rails_#{rails_version_underscored}" do
56
+ desc "Test Rails #{rails_version}"
57
+ task :"test_rails_#{rails_version.gsub(".", "_")}" do
58
58
  env = { 'BUNDLE_GEMFILE' => gemfile }
59
59
  TestTasks.run_one(env)
60
60
  end
61
- end
61
+ end
@@ -18,13 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.files.grep(%r{^bin/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "activerecord", ">= 4.0"
21
+ spec.add_dependency "activerecord", ">= 6.0"
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.6"
23
+ spec.add_development_dependency "bundler"
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency "rspec", "~> 3.0"
26
26
  spec.add_development_dependency "pry"
27
- spec.add_development_dependency "sqlite3"
28
- spec.add_development_dependency "pg"
29
- spec.add_development_dependency "mysql2"
30
27
  end
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env bash
2
+
3
+ GREEN='\033[0;32m'
4
+ RESET_COLOR='\033[0m'
5
+
6
+ if [ -n "$1" ]; then cat <<'HELP'; exit; fi
7
+ Usage: bin/create-db-users
8
+ Create the active_record_union database users for all the supported databases.
9
+ If the `DB` environment variable is set, do the above only for that database.
10
+ HELP
11
+
12
+ USER='active_record_union'
13
+ PASS='active_record_union'
14
+
15
+ set -e
16
+ log() { if [ -t 1 ]; then echo -e >&2 "${GREEN}create-db-users: $@${RESET_COLOR}"; else echo >&2 "$@"; fi }
17
+
18
+ create_mysql_user() {
19
+ if mysql -s -u"$USER" -p"$PASS" -e '' 2>/dev/null; then return; fi
20
+ log "Creating MySQL '$USER' user. MySQL root password required."
21
+ mysql --verbose -uroot -p <<SQL
22
+ CREATE USER '$USER'@'localhost' IDENTIFIED BY '$PASS';
23
+ GRANT ALL PRIVILEGES ON \`test_active_record_union\`.* TO '$USER'@'localhost';
24
+ SQL
25
+ }
26
+
27
+ create_postgresql_user() {
28
+ if PGPASSWORD="$PASS" psql -h 127.0.0.1 postgres -U $USER -c ''; then return; fi
29
+ log "Creating Postgres '$USER' user."
30
+ local cmd='psql postgres'
31
+ if ! $cmd -c '' 2>/dev/null; then
32
+ log "sudo required:"
33
+ cmd="sudo -u ${PG_DAEMON_USER:-postgres} psql postgres"
34
+ fi
35
+ # need to also create database first time
36
+ $cmd --echo-all <<SQL
37
+ CREATE ROLE $USER LOGIN PASSWORD '$PASS';
38
+ ALTER ROLE $USER CREATEDB;
39
+ CREATE DATABASE active_record_union;
40
+ SQL
41
+ }
42
+
43
+ [ -z "$DB" -o "$DB" = 'mysql2' ] && create_mysql_user
44
+ [ -z "$DB" -o "$DB" = 'postgresql' ] && create_postgresql_user
@@ -18,32 +18,31 @@ module ActiveRecord
18
18
  private
19
19
 
20
20
  def set_operation(operation, relation_or_where_arg, *args)
21
- other = if args.size == 0 && Relation === relation_or_where_arg
21
+ other = if args.empty? && relation_or_where_arg.is_a?(Relation)
22
22
  relation_or_where_arg
23
23
  else
24
- @klass.where(relation_or_where_arg, *args)
24
+ self.klass.where(relation_or_where_arg, *args)
25
25
  end
26
26
 
27
27
  verify_relations_for_set_operation!(operation, self, other)
28
28
 
29
+ left = self.arel.ast
30
+ right = other.arel.ast
31
+
29
32
  # Postgres allows ORDER BY in the UNION subqueries if each subquery is surrounded by parenthesis
30
- # but SQLite does not allow parens around the subqueries; you will have to explicitly do `relation.reorder(nil)` in SQLite
31
- if Arel::Visitors::SQLite === self.connection.visitor
32
- left, right = self.ast, other.ast
33
- else
34
- left, right = Arel::Nodes::Grouping.new(self.ast), Arel::Nodes::Grouping.new(other.ast)
33
+ # but SQLite does not allow parens around the subqueries
34
+ unless self.connection.visitor.is_a?(Arel::Visitors::SQLite)
35
+ left = Arel::Nodes::Grouping.new(left)
36
+ right = Arel::Nodes::Grouping.new(right)
35
37
  end
36
38
 
37
39
  set = SET_OPERATION_TO_AREL_CLASS[operation].new(left, right)
38
- from = Arel::Nodes::TableAlias.new(set, @klass.arel_table.name)
39
- if ActiveRecord::VERSION::MAJOR >= 5
40
- relation = @klass.unscoped.spawn
41
- relation.from_clause = UnionFromClause.new(from, nil, self.bound_attributes + other.bound_attributes)
42
- else
43
- relation = @klass.unscoped.from(from)
44
- relation.bind_values = self.arel.bind_values + self.bind_values + other.arel.bind_values + other.bind_values
45
- end
46
- relation
40
+ from = Arel::Nodes::TableAlias.new(set, self.klass.arel_table.name)
41
+ build_union_relation(from, other)
42
+ end
43
+
44
+ def build_union_relation(arel_table_alias, _other)
45
+ self.klass.unscoped.from(arel_table_alias)
47
46
  end
48
47
 
49
48
  def verify_relations_for_set_operation!(operation, *relations)
@@ -63,19 +62,6 @@ module ActiveRecord
63
62
  raise ArgumentError.new("Cannot #{operation} relation with eager load.")
64
63
  end
65
64
  end
66
-
67
- if ActiveRecord::VERSION::MAJOR >= 5
68
- class UnionFromClause < ActiveRecord::Relation::FromClause
69
- def initialize(value, name, bound_attributes)
70
- super(value, name)
71
- @bound_attributes = bound_attributes
72
- end
73
-
74
- def binds
75
- @bound_attributes
76
- end
77
- end
78
- end
79
65
  end
80
66
  end
81
67
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordUnion
2
- VERSION = "1.2.0"
2
+ VERSION = "1.4.0"
3
3
  end
data/rails_6.0.gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in active_record_union.gemspec
4
+ gemspec
5
+
6
+ gem 'rails', '~> 6.0.0'
7
+
8
+ # https://github.com/rails/rails/blob/v6.0.6.1/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
9
+ gem "pg", ">= 0.18", "< 2.0"
10
+
11
+ # https://github.com/rails/rails/blob/v6.0.2/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L13
12
+ gem "sqlite3", "~> 1.4"
13
+
14
+ # https://github.com/rails/rails/blob/v6.0.6.1/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
15
+ gem "mysql2", ">= 0.4.4"
16
+
data/rails_6.1.gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in active_record_union.gemspec
4
+ gemspec
5
+
6
+ gem 'rails', '~> 6.1.0'
7
+
8
+ # https://github.com/rails/rails/blob/v6.1.7.10/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
9
+ gem "pg", "~> 1.1"
10
+
11
+ # https://github.com/rails/rails/blob/v6.1.2/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L13
12
+ gem "sqlite3", "~> 1.4"
13
+
14
+ # https://github.com/rails/rails/blob/v6.1.7.10/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
15
+ gem "mysql2", "~> 0.5"
16
+
data/rails_7.0.gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in active_record_union.gemspec
6
+ gemspec
7
+
8
+ gem 'rails', '~> 7.0.0'
9
+
10
+ # https://github.com/rails/rails/blob/v7.0.2/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L13
11
+ gem 'sqlite3', '~> 1.4'
12
+
13
+ # https://github.com/rails/rails/blob/v7.0.2/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L4
14
+ gem 'pg', '~> 1.1'
15
+
16
+ # https://github.com/rails/rails/blob/v7.0.2/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L6
17
+ gem 'mysql2', '~> 0.5'
data/rails_7.1.gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in active_record_union.gemspec
6
+ gemspec
7
+
8
+ gem 'rails', '~> 7.1.0'
9
+
10
+ # https://github.com/rails/rails/blob/v7.1.2/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L13
11
+ gem 'sqlite3', '~> 1.4'
12
+
13
+ # https://github.com/rails/rails/blob/v7.1.2/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L4
14
+ gem 'pg', '~> 1.1'
15
+
16
+ # https://github.com/rails/rails/blob/v7.1.2/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L6
17
+ gem 'mysql2', '~> 0.5'
data/rails_7.2.gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in active_record_union.gemspec
6
+ gemspec
7
+
8
+ gem 'rails', '~> 7.2.0'
9
+
10
+ # https://github.com/rails/rails/blob/v7.2.0/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L13
11
+ gem 'sqlite3', '>= 1.4'
12
+
13
+ # https://github.com/rails/rails/blob/v7.2.0/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L4
14
+ gem 'pg', '~> 1.1'
15
+
16
+ # https://github.com/rails/rails/blob/v7.2.0/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L6
17
+ gem 'mysql2', '~> 0.5'
data/rails_8.0.gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in active_record_union.gemspec
6
+ gemspec
7
+
8
+ gem 'rails', '~> 8.0.0'
9
+
10
+ # https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L13
11
+ gem 'sqlite3', '>= 2.1'
12
+
13
+ # https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L4
14
+ gem 'pg', '~> 1.1'
15
+
16
+ # https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L6
17
+ gem 'mysql2', '~> 0.5'
data/spec/spec_helper.rb CHANGED
@@ -9,6 +9,7 @@ Databases.connect_to_sqlite
9
9
 
10
10
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
11
11
  RSpec.configure do |config|
12
+ config.backtrace_inclusion_patterns << %r{gems/([0-9.])+/gems/(?!rspec|capybara)} if ENV['BACKTRACE']
12
13
  # Run specs in random order to surface order dependencies. If you find an
13
14
  # order dependency and want to debug it, you can fix the order by providing
14
15
  # the seed, which is printed after each run.
@@ -11,24 +11,47 @@ module Databases
11
11
 
12
12
  def connect_to_postgres
13
13
  ActiveRecord::Base.establish_connection(
14
- adapter: "postgresql"
14
+ adapter: "postgresql",
15
+ host: ENV.fetch('DB_HOST', 'localhost'),
16
+ username: ENV.fetch("POSTGRES_USER", 'active_record_union'),
17
+ password: ENV.fetch("POSTGRES_PASSWORD", 'active_record_union')
15
18
  )
16
- ActiveRecord::Base.connection.recreate_database("test_active_record_union")
19
+ try_to_drop_database
20
+ ActiveRecord::Base.connection.create_database("test_active_record_union")
17
21
  ActiveRecord::Base.establish_connection(
18
22
  adapter: "postgresql",
19
- database: "test_active_record_union"
23
+ host: ENV.fetch('DB_HOST', 'localhost'),
24
+ username: ENV.fetch("POSTGRES_USER", 'active_record_union'),
25
+ password: ENV.fetch("POSTGRES_PASSWORD", 'active_record_union'),
26
+ database: ENV.fetch("POSTGRES_DB", "test_active_record_union")
20
27
  )
21
28
  load("support/models.rb")
22
29
  end
23
30
 
31
+ def try_to_drop_database
32
+ ActiveRecord::Base.connection.drop_database("test_active_record_union")
33
+ rescue ActiveRecord::NoDatabaseError
34
+ $stderr.puts "Can't drop database 'test_active_record_union' as it doesn't exist"
35
+ rescue ActiveRecord::ActiveRecordError => e
36
+ $stderr.puts "Can't drop database 'test_active_record_union' (but continuing anyway): #{e}"
37
+ rescue => e
38
+ $stderr.puts "Other error (#{e.class.name}) dropping database 'test_active_record_union' (but continuing anyway): #{e}"
39
+ end
40
+
24
41
  def connect_to_mysql
25
42
  ActiveRecord::Base.establish_connection(
26
- adapter: "mysql2"
43
+ adapter: "mysql2",
44
+ host: ENV.fetch('DB_HOST', 'localhost'),
45
+ username: ENV.fetch("MYSQL_USER", "active_record_union"),
46
+ password: ENV.fetch("MYSQL_PASSWORD", "active_record_union")
27
47
  )
28
48
  ActiveRecord::Base.connection.recreate_database("test_active_record_union")
29
49
  ActiveRecord::Base.establish_connection(
30
50
  adapter: "mysql2",
31
- database: "test_active_record_union"
51
+ host: ENV.fetch('DB_HOST', 'localhost'),
52
+ username: ENV.fetch("MYSQL_USER", "active_record_union"),
53
+ password: ENV.fetch("MYSQL_PASSWORD", "active_record_union"),
54
+ database: ENV.fetch("MYSQL_DB", "test_active_record_union")
32
55
  )
33
56
  load("support/models.rb")
34
57
  end
data/spec/union_spec.rb CHANGED
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe ActiveRecord::Relation do
4
4
  TIME = Time.utc(2014, 7, 19, 0, 0, 0)
5
- SQL_TIME = ActiveRecord::VERSION::MAJOR >= 5 ? "2014-07-19 00:00:00" : "2014-07-19 00:00:00.000000"
5
+ SQL_TIME = "2014-07-19 00:00:00"
6
6
 
7
7
  describe ".union" do
8
8
  it "returns an ActiveRecord::Relation" do
@@ -34,18 +34,30 @@ describe ActiveRecord::Relation do
34
34
  expect(union.to_sql.squish).to eq(
35
35
  "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '#{SQL_TIME}') ) \"posts\""
36
36
  )
37
- expect(union.arel.to_sql.squish).to eq(
38
- "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '#{SQL_TIME}') ) \"posts\""
39
- )
40
- expect{union.to_a}.to_not raise_error
37
+ if ActiveRecord.version >= Gem::Version.new("7.2.0")
38
+ expect(union.arel.to_sql.squish).to eq(
39
+ "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > ?) ) \"posts\""
40
+ )
41
+ expect(bind_values_from_arel(union.arel, Post.arel_table)).to eq([1, TIME])
42
+ else
43
+ expect(union.arel.to_sql.squish).to eq(
44
+ "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '#{SQL_TIME}') ) \"posts\""
45
+ )
46
+ expect(bind_values_from_arel(union.arel, Post.arel_table)).to eq([1])
47
+ end
48
+ expect { union.to_a }.to_not raise_error
41
49
  end
42
50
 
43
51
  def bind_values_from_relation(relation)
44
- if ActiveRecord::VERSION::MAJOR >= 5
45
- relation.bound_attributes.map { |a| a.value_for_database }
46
- else
47
- (relation.arel.bind_values + relation.bind_values).map { |_column, value| value }
48
- end
52
+ bind_values_from_arel(relation.arel, relation.arel_table)
53
+ end
54
+
55
+ def bind_values_from_arel(arel, arel_table)
56
+ collector = Arel::Collectors::Bind.new
57
+ collector.define_singleton_method(:preparable=) { |_preparable| } if ActiveRecord.version.between?(Gem::Version.new("6.1.0"), Gem::Version.new("7.2.99"))
58
+ arel_table.class.engine.connection.visitor.accept(
59
+ arel.ast, collector
60
+ ).value.map { |v| v.try(:value) || v }
49
61
  end
50
62
 
51
63
  it "binds values properly" do
@@ -68,16 +80,16 @@ describe ActiveRecord::Relation do
68
80
  bind_values = bind_values_from_relation union
69
81
  expect(bind_values).to eq([true, 11])
70
82
 
71
-
72
83
  expect(union.to_sql.squish).to eq(
73
- "SELECT \"users\".* FROM ( SELECT \"users\".* FROM \"users\" INNER JOIN \"posts\" ON \"posts\".\"user_id\" = \"users\".\"id\" AND \"posts\".\"draft\" = 't' UNION SELECT \"users\".* FROM \"users\" WHERE \"users\".\"id\" = 11 ) \"users\""
84
+ "SELECT \"users\".* FROM ( SELECT \"users\".* FROM \"users\" INNER JOIN \"posts\" ON \"posts\".\"draft\" = 1 AND \"posts\".\"user_id\" = \"users\".\"id\" UNION SELECT \"users\".* FROM \"users\" WHERE \"users\".\"id\" = 11 ) \"users\""
74
85
  )
75
86
  expect{union.to_a}.to_not raise_error
76
87
  end
77
88
 
78
89
  it "doesn't repeat default scopes" do
79
90
  expect(Time).to receive(:now) { Time.utc(2014, 7, 24, 0, 0, 0) }
80
- sql_now = "2014-07-24 00:00:00#{".000000" if ActiveRecord::VERSION::MAJOR < 5}"
91
+
92
+ sql_now = "2014-07-24 00:00:00"
81
93
 
82
94
  class PublishedPost < ActiveRecord::Base
83
95
  self.table_name = "posts"
@@ -101,9 +113,15 @@ describe ActiveRecord::Relation do
101
113
 
102
114
  context "in SQLite" do
103
115
  it "lets ORDER BY in query subselects throw a syntax error" do
104
- expect(union.to_sql.squish).to eq(
105
- "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ORDER BY \"posts\".\"created_at\" ASC UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '#{SQL_TIME}') ORDER BY \"posts\".\"created_at\" ASC ) \"posts\" ORDER BY \"posts\".\"created_at\" ASC"
106
- )
116
+ if ActiveRecord.version >= Gem::Version.new("7.2.0")
117
+ expect(union.to_sql.squish).to eq(
118
+ "SELECT \"posts\".* FROM ( (SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ORDER BY \"posts\".\"created_at\" ASC) UNION (SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00') ORDER BY \"posts\".\"created_at\" ASC) ) \"posts\" ORDER BY \"created_at\" ASC"
119
+ )
120
+ else
121
+ expect(union.to_sql.squish).to eq(
122
+ "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ORDER BY \"posts\".\"created_at\" ASC UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00') ORDER BY \"posts\".\"created_at\" ASC ) \"posts\" ORDER BY \"created_at\" ASC"
123
+ )
124
+ end
107
125
  expect{union.to_a}.to raise_error(ActiveRecord::StatementInvalid)
108
126
  end
109
127
  end
@@ -112,8 +130,9 @@ describe ActiveRecord::Relation do
112
130
  it "wraps query subselects in parentheses to allow ORDER BY clauses" do
113
131
  Databases.with_postgres do
114
132
  expect(union.to_sql.squish).to eq(
115
- "SELECT \"posts\".* FROM ( (SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ORDER BY \"posts\".\"created_at\" ASC) UNION (SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '#{SQL_TIME}') ORDER BY \"posts\".\"created_at\" ASC) ) \"posts\" ORDER BY \"posts\".\"created_at\" ASC"
133
+ "SELECT \"posts\".* FROM ( (SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = 1 ORDER BY \"posts\".\"created_at\" ASC) UNION (SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00') ORDER BY \"posts\".\"created_at\" ASC) ) \"posts\" ORDER BY \"created_at\" ASC"
116
134
  )
135
+
117
136
  expect{union.to_a}.to_not raise_error
118
137
  end
119
138
  end
@@ -123,8 +142,9 @@ describe ActiveRecord::Relation do
123
142
  it "wraps query subselects in parentheses to allow ORDER BY clauses" do
124
143
  Databases.with_mysql do
125
144
  expect(union.to_sql.squish).to eq(
126
- "SELECT `posts`.* FROM ( (SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 1 ORDER BY `posts`.`created_at` ASC) UNION (SELECT `posts`.* FROM `posts` WHERE (created_at > '#{SQL_TIME}') ORDER BY `posts`.`created_at` ASC) ) `posts` ORDER BY `posts`.`created_at` ASC"
145
+ "SELECT `posts`.* FROM ( (SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 1 ORDER BY `posts`.`created_at` ASC) UNION (SELECT `posts`.* FROM `posts` WHERE (created_at > '2014-07-19 00:00:00') ORDER BY `posts`.`created_at` ASC) ) `posts` ORDER BY `created_at` ASC"
127
146
  )
147
+
128
148
  expect{union.to_a}.to_not raise_error
129
149
  end
130
150
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record_union
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Hempel
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-27 00:00:00.000000000 Z
11
+ date: 2025-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.0'
19
+ version: '6.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: '4.0'
26
+ version: '6.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.6'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.6'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,48 +80,6 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: sqlite3
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: pg
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: mysql2
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
83
  description: UNIONs in ActiveRecord! Adds proper union and union_all methods to ActiveRecord::Relation.
126
84
  email:
127
85
  - plasticchicken@gmail.com
@@ -129,18 +87,24 @@ executables: []
129
87
  extensions: []
130
88
  extra_rdoc_files: []
131
89
  files:
90
+ - ".github/workflows/testing.yml"
132
91
  - ".gitignore"
133
- - ".travis.yml"
92
+ - Gemfile
134
93
  - LICENSE.txt
135
94
  - README.md
136
95
  - Rakefile
137
96
  - active_record_union.gemspec
138
97
  - bin/console
98
+ - bin/create-db-users
139
99
  - lib/active_record_union.rb
140
100
  - lib/active_record_union/active_record/relation/union.rb
141
101
  - lib/active_record_union/version.rb
142
- - rails_4_2.gemfile
143
- - rails_5_0.gemfile
102
+ - rails_6.0.gemfile
103
+ - rails_6.1.gemfile
104
+ - rails_7.0.gemfile
105
+ - rails_7.1.gemfile
106
+ - rails_7.2.gemfile
107
+ - rails_8.0.gemfile
144
108
  - spec/spec_helper.rb
145
109
  - spec/support/databases.rb
146
110
  - spec/support/models.rb
@@ -149,7 +113,7 @@ homepage: https://github.com/brianhempel/active_record_union
149
113
  licenses:
150
114
  - Public Domain
151
115
  metadata: {}
152
- post_install_message:
116
+ post_install_message:
153
117
  rdoc_options: []
154
118
  require_paths:
155
119
  - lib
@@ -164,9 +128,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
128
  - !ruby/object:Gem::Version
165
129
  version: '0'
166
130
  requirements: []
167
- rubyforge_project:
168
- rubygems_version: 2.4.5.1
169
- signing_key:
131
+ rubygems_version: 3.4.10
132
+ signing_key:
170
133
  specification_version: 4
171
134
  summary: UNIONs in ActiveRecord! Adds proper union and union_all methods to ActiveRecord::Relation.
172
135
  test_files:
@@ -175,3 +138,4 @@ test_files:
175
138
  - spec/support/models.rb
176
139
  - spec/union_spec.rb
177
140
  - bin/console
141
+ - bin/create-db-users
data/.travis.yml DELETED
@@ -1,19 +0,0 @@
1
- language: ruby
2
- addons:
3
- postgresql: "9.4"
4
- rvm:
5
- - 2.3.1
6
- - 2.2.5
7
- - 2.1.8
8
- - 2.0.0
9
- gemfile:
10
- - rails_4_2.gemfile
11
- - rails_5_0.gemfile
12
- matrix:
13
- exclude:
14
- # Rails 5 requires Ruby 2.2+:
15
- - rvm: 2.1.8
16
- gemfile: rails_5_0.gemfile
17
- - rvm: 2.0.0
18
- gemfile: rails_5_0.gemfile
19
- script: bundle exec rspec
data/rails_4_2.gemfile DELETED
@@ -1,6 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in active_record_union.gemspec
4
- gemspec
5
-
6
- gem 'rails', '~> 4.2.6'
data/rails_5_0.gemfile DELETED
@@ -1,6 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in active_record_union.gemspec
4
- gemspec
5
-
6
- gem 'rails', ['>= 5.0.0.rc2', '< 5.1']