active_record_union 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3eba1bb2ac0137d8d84b62bb48f45e8c90f78efe
4
+ data.tar.gz: ef18422b1efeabda133e5e2d86985c918759f1b8
5
+ SHA512:
6
+ metadata.gz: e318f5d727ea3e1483c67638b824293840ba75f7d0191bf7490d62a32bc17c9dbd8fd7403f652f1fd51294f97b8bd8e33e4445cd83ac36e3956ded6b978efc12
7
+ data.tar.gz: 961b39db5ef83a66708c6424356189e60837d3eb2068a1c0464da7d7ddc2154cb116bf596f7f73b8b3c46bdffbafafa0774a20c4c0798b5774df71e12b246717
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in active_record_union.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,3 @@
1
+ ActiveRecordUnion is dedicated to the public domain by its author, Brian Hempel. No rights are reserved. No restrictions are placed on the use of ActiveRecordUnion. That freedom also means, of course, that no warrenty of fitness is claimed; use ActiveRecordUnion at your own risk.
2
+
3
+ Public domain dedication is explained by the CC0 1.0 summary (and only the summary) at https://creativecommons.org/publicdomain/zero/1.0/
data/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # ActiveRecordUnion
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/active_record_union.svg)](http://badge.fury.io/rb/active_record_union)
4
+ [![Build Status](https://travis-ci.org/brianhempel/active_record_union.svg)](https://travis-ci.org/brianhempel/active_record_union)
5
+
6
+ Use unions on ActiveRecord scopes without ugliness.
7
+
8
+ If you find yourself writing `pluck(:id)` and then feeding that into another query, you may be able to reduce the number of database requests by using a nested query or a UNION without writing crazy JOIN statements.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'active_record_union'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install active_record_union
25
+
26
+ ## Usage
27
+
28
+ ActiveRecordUnion adds a `union` method to `ActiveRecord::Relation` so we can easily gather together queries on mutiple scopes.
29
+
30
+ Consider some users with posts:
31
+
32
+ ```ruby
33
+ class User < ActiveRecord::Base
34
+ has_many :posts
35
+ end
36
+
37
+ class Post < ActiveRecord::Base
38
+ belongs_to :user
39
+
40
+ scope :published, -> { where("published_at < ?", Time.now) }
41
+ end
42
+ ```
43
+
44
+ With ActiveRecordUnion, we can do:
45
+
46
+ ```ruby
47
+ # the current user's (draft) posts and all published posts from anyone
48
+ current_user.posts.union(Post.published)
49
+ ```
50
+
51
+ Which is equivalent to the following SQL: [<a href="#footnote-1">1</a>]
52
+
53
+ ```sql
54
+ SELECT "posts".* FROM (
55
+ SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = ?
56
+ UNION
57
+ SELECT "posts".* FROM "posts" WHERE (published_at < '2014-07-19 16:04:21.918366')
58
+ ) posts
59
+ ```
60
+
61
+ Because the `union` method returns another `ActiveRecord::Relation`, we can run further queries on the union.
62
+
63
+ ```ruby
64
+ current_user.posts.union(Post.published).where(id: [6, 7])
65
+ ```
66
+ ```sql
67
+ SELECT "posts".* FROM (
68
+ SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = ?
69
+ UNION
70
+ SELECT "posts".* FROM "posts" WHERE (published_at < '2014-07-19 16:06:04.460771')
71
+ ) posts WHERE "posts"."id" IN (6, 7)
72
+ ```
73
+
74
+ The `union` method can also accepts anything that `where` does.
75
+
76
+ ```ruby
77
+ current_user.posts.union("published_at < ?", Time.now)
78
+ # equivalent to...
79
+ current_user.posts.union(Post.where("published_at < ?", Time.now))
80
+ ```
81
+
82
+ We can also chain `union` calls to UNION more than two scopes, though the UNIONs will be nested which may not be the prettiest SQL.
83
+
84
+ ```ruby
85
+ user_1.posts.union(user_2.posts).union(Post.published)
86
+ # equivalent to...
87
+ [user_1.posts, user_2.posts, Post.published].inject(:union)
88
+ ```
89
+ ```sql
90
+ SELECT "posts".* FROM (
91
+ SELECT "posts".* FROM (
92
+ SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = ?
93
+ UNION
94
+ SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = ?
95
+ ) posts
96
+ UNION
97
+ SELECT "posts".* FROM "posts" WHERE (published_at < '2014-07-19 16:12:45.882648')
98
+ ) posts
99
+ ```
100
+
101
+ <a name="footnote-1"></a>[1] Note: the `?` in the SQL is bound to the correct value when ActiveRecord executes the query. Also, the SQL examples here were generated for a SQLite database. The syntax generated for other databases may vary slightly.
102
+
103
+ ## Another nifty way to reduce extra queries
104
+
105
+ ActiveRecord already supports turning scopes into nested queries in WHERE clauses. The nested relation defaults to selecting `id` by default.
106
+
107
+ For example, if a user `has_and_belongs_to_many :favorited_posts`, we can quickly find which of the current user's posts are liked by a certain other user.
108
+
109
+ ```ruby
110
+ current_user.posts.where(id: other_user.favorited_posts)
111
+ ```
112
+ ```sql
113
+ SELECT "posts".* FROM "posts"
114
+ WHERE "posts"."user_id" = ?
115
+ AND "posts"."id" IN (
116
+ SELECT "posts"."id"
117
+ FROM "posts" INNER JOIN "user_favorited_posts" ON "posts"."id" = "user_favorited_posts"."post_id"
118
+ WHERE "user_favorited_posts"."user_id" = ?
119
+ )
120
+ ```
121
+
122
+ If we want to select something other than `id`, we use `select` to specify. The following is equivalent to the above, but the query is done against the join table.
123
+
124
+ ```ruby
125
+ current_user.posts.where(id: UserFavoritedPost.where(user_id: other_user.id).select(:post_id))
126
+ ```
127
+ ```sql
128
+ SELECT "posts".* FROM "posts"
129
+ WHERE "posts"."user_id" = ?
130
+ AND "posts"."id" IN (
131
+ SELECT "user_favorited_posts"."post_id"
132
+ FROM "user_favorited_posts"
133
+ WHERE "user_favorited_posts"."user_id" = 2
134
+ )
135
+ ```
136
+
137
+ (The above example is illustrative only. It might be better with a JOIN.)
138
+
139
+ ## State of the Union in ActiveRecord
140
+
141
+ Why does this gem exist?
142
+
143
+ Right now in ActiveRecord, if we call `scope.union` we get an `Arel::Nodes::Union` object instead of an `ActiveRecord::Relation`.
144
+
145
+ We could call `to_sql` on the Arel object and then use `find_by_sql`, but that's not super clean and if the original scopes included an association, then the `to_sql` may produce a query with values that need to be bound (represented by `?`s in the SQL) and we have to provide those ourselves. (E.g. `user.posts.to_sql` produces `SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = ?`.)
146
+
147
+ While ActiveRecord may eventually have the ability to cleanly perform UNIONs, it's currently stalled. If you're interested, the relevant URLs as of July 2014 are:
148
+
149
+ https://github.com/rails/rails/issues/939 and
150
+ https://github.com/rails/arel/pull/239 and
151
+ https://github.com/yakaz/rails/commit/29b8ebd187e0888d5e71b2e1e4a12334860bc76c
152
+
153
+ This is a gem not a Rails pull request because the standard of code quality for a PR is a bit higher, and we'd have to wait for the PR to be merged and relased to use UNIONs. That said, the code here is fairly clean and it may end up in a PR sometime.
154
+
155
+ ## License
156
+
157
+ ActiveRecordUnion is dedicated to the public domain by its author, Brian Hempel. No rights are reserved. No restrictions are placed on the use of ActiveRecordUnion. That freedom also means, of course, that no warrenty of fitness is claimed; use ActiveRecordUnion at your own risk.
158
+
159
+ Public domain dedication is explained by the CC0 1.0 summary (and only the summary) at https://creativecommons.org/publicdomain/zero/1.0/
160
+
161
+ ## Contributing
162
+
163
+ 1. Fork it ( https://github.com/[my-github-username]/active_record_union/fork )
164
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
165
+ 3. Run the tests with `rspec`
166
+ 4. There is also a `bin/console` command to load up a REPL for playing around
167
+ 5. Commit your changes (`git commit -am 'Add some feature'`)
168
+ 6. Push to the branch (`git push origin my-new-feature`)
169
+ 7. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => :spec
4
+
5
+ desc "Run the tests"
6
+ task :spec do
7
+ exec("bundle exec rspec")
8
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'active_record_union/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "active_record_union"
8
+ spec.version = ActiveRecordUnion::VERSION
9
+ spec.authors = ["Brian Hempel"]
10
+ spec.email = ["plasticchicken@gmail.com"]
11
+ spec.summary = %q{UNIONs in ActiveRecord! Adds a proper union method to ActiveRecord::Relation.}
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/brianhempel/active_record_union"
14
+ spec.license = "Public Domain"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ # spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.files.grep(%r{^bin/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activerecord", ">= 4.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "pry"
27
+ spec.add_development_dependency "sqlite3"
28
+ end
data/bin/console ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This is for development only.
4
+
5
+ require "bundler/setup"
6
+
7
+ Bundler.require(:development)
8
+ require "active_record_union"
9
+
10
+ ActiveRecord::Base.establish_connection(
11
+ adapter: "sqlite3",
12
+ database: ":memory:"
13
+ )
14
+
15
+ require File.expand_path("../../spec/support/models.rb", __FILE__)
16
+
17
+ # extensions over models.rb to help with making the README
18
+
19
+ class User
20
+ has_and_belongs_to_many :favorited_posts,
21
+ class_name: "Post",
22
+ join_table: "user_favorited_posts"
23
+ end
24
+
25
+ class UserFavoritedPost < ActiveRecord::Base
26
+ connection.create_table :user_favorited_posts, force: true do |t|
27
+ t.integer :post_id
28
+ t.integer :user_id
29
+ end
30
+ end
31
+
32
+ class Post
33
+ scope :published, -> { where("published_at < ?", Time.now) }
34
+ end
35
+
36
+ binding.pry
@@ -0,0 +1,9 @@
1
+ require "active_record_union/version"
2
+ require "active_record"
3
+ require "active_record_union/active_record/relation/union"
4
+
5
+ module ActiveRecord
6
+ class Relation
7
+ include Union
8
+ end
9
+ end
@@ -0,0 +1,41 @@
1
+ module ActiveRecord
2
+ class Relation
3
+ module Union
4
+ def union(relation_or_where_arg, *args)
5
+ other = relation_or_where_arg if args.size == 0 && Relation === relation_or_where_arg
6
+ other ||= @klass.where(relation_or_where_arg, *args)
7
+
8
+ verify_union_relations!(self, other)
9
+
10
+ union = self.arel.union(other)
11
+ from = Arel::Nodes::TableAlias.new(
12
+ union,
13
+ Arel::Nodes::SqlLiteral.new(@klass.arel_table.name)
14
+ )
15
+
16
+ relation = @klass.unscoped.from(from)
17
+ relation.bind_values = self.bind_values + other.bind_values + relation.bind_values
18
+ relation
19
+ end
20
+
21
+ private
22
+
23
+ def verify_union_relations!(*args)
24
+ includes_relations = args.select { |r| r.includes_values.any? }
25
+ if includes_relations.any?
26
+ raise ArgumentError.new("Cannot union relation with includes.")
27
+ end
28
+
29
+ preload_relations = args.select { |r| r.preload_values.any? }
30
+ if preload_relations.any?
31
+ raise ArgumentError.new("Cannot union relation with preload.")
32
+ end
33
+
34
+ eager_load_relations = args.select { |r| r.eager_load_values.any? }
35
+ if eager_load_relations.any?
36
+ raise ArgumentError.new("Cannot union relation with eager load.")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveRecordUnion
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,41 @@
1
+ require "active_record_union"
2
+
3
+ ActiveRecord::Base.establish_connection(
4
+ adapter: "sqlite3",
5
+ database: ":memory:"
6
+ )
7
+
8
+ require "support/models"
9
+
10
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
11
+ RSpec.configure do |config|
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = :random
17
+
18
+ # Seed global randomization in this process using the `--seed` CLI option.
19
+ # Setting this allows you to use `--seed` to deterministically reproduce
20
+ # test failures related to randomization by passing the same `--seed` value
21
+ # as the one that triggered the failure.
22
+ Kernel.srand config.seed
23
+
24
+ config.expect_with :rspec do |expectations|
25
+ # Enable only the newer, non-monkey-patching expect syntax.
26
+ # For more details, see:
27
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
28
+ expectations.syntax = :expect
29
+ end
30
+
31
+ config.mock_with :rspec do |mocks|
32
+ # Enable only the newer, non-monkey-patching expect syntax.
33
+ # For more details, see:
34
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
35
+ mocks.syntax = :expect
36
+
37
+ # Prevents you from mocking or stubbing a method that does not exist on
38
+ # a real object. This is generally recommended.
39
+ mocks.verify_partial_doubles = true
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ class User < ActiveRecord::Base
2
+ connection.create_table :users, force: true do |t|
3
+ end
4
+
5
+ has_many :posts
6
+ end
7
+
8
+ class Post < ActiveRecord::Base
9
+ connection.create_table :posts, force: true do |t|
10
+ t.integer :user_id
11
+ t.timestamps
12
+ end
13
+
14
+ belongs_to :user
15
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRecord::Relation do
4
+ describe ".union" do
5
+ it "returns an ActiveRecord::Relation" do
6
+ expect(User.all.union(User.all)).to be_kind_of(ActiveRecord::Relation)
7
+ end
8
+
9
+ it "requires an argument" do
10
+ expect{User.all.union}.to raise_error(ArgumentError)
11
+ end
12
+
13
+ it "explodes if asked to union a relation with includes" do
14
+ expect{User.all.union(User.includes(:posts))}.to raise_error(ArgumentError)
15
+ expect{User.includes(:posts).union(User.all)}.to raise_error(ArgumentError)
16
+ end
17
+
18
+ it "explodes if asked to union a relation with preload values" do
19
+ expect{User.all.union(User.preload(:posts))}.to raise_error(ArgumentError)
20
+ expect{User.preload(:posts).union(User.all)}.to raise_error(ArgumentError)
21
+ end
22
+
23
+ it "explodes if asked to union a relation with eager loading" do
24
+ expect{User.all.union(User.eager_load(:posts))}.to raise_error(ArgumentError)
25
+ expect{User.eager_load(:posts).union(User.all)}.to raise_error(ArgumentError)
26
+ end
27
+
28
+ it "works" do
29
+ union = User.new.posts.union(Post.where("created_at > ?", Time.utc(2014, 7, 19, 0, 0, 0)))
30
+
31
+ expect(union.to_sql).to eq(
32
+ "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) posts"
33
+ )
34
+ end
35
+
36
+ it "binds values properly" do
37
+ user1 = User.new(id: 1)
38
+ user2 = User.new(id: 2)
39
+ user3 = User.new(id: 3)
40
+
41
+ union = user1.posts.union(user2.posts).where.not(id: user3.posts)
42
+ bind_values = union.bind_values.map { |column, value| value }
43
+
44
+ expect(bind_values).to eq([1, 2, 3])
45
+ end
46
+
47
+ it "doesn't repeat default scopes" do
48
+ expect(Time).to receive(:now) { Time.utc(2014, 7, 24, 0, 0, 0) }
49
+
50
+ class PublishedPost < ActiveRecord::Base
51
+ self.table_name = "posts"
52
+ default_scope { where("published_at < ?", Time.now) }
53
+ end
54
+
55
+ union = PublishedPost.where("created_at > ?", Time.utc(2014, 7, 19, 0, 0, 0)).union(User.new.posts)
56
+
57
+ expect(union.to_sql).to eq(
58
+ "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE (published_at < '2014-07-24 00:00:00.000000') AND (created_at > '2014-07-19 00:00:00.000000') UNION SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? ) posts"
59
+ )
60
+ end
61
+
62
+ context "builds a scope when given" do
63
+ it "a hash" do
64
+ union = User.new.posts.union(id: 1)
65
+
66
+ expect(union.to_sql).to eq(
67
+ "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? UNION SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\" = 1 ) posts"
68
+ )
69
+ end
70
+
71
+ it "multiple arguments" do
72
+ union = User.new.posts.union("created_at > ?", Time.utc(2014, 7, 19, 0, 0, 0))
73
+
74
+ expect(union.to_sql).to eq(
75
+ "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? UNION SELECT \"posts\".* FROM \"posts\" WHERE (created_at > '2014-07-19 00:00:00.000000') ) posts"
76
+ )
77
+ end
78
+
79
+ it "arel" do
80
+ union = User.new.posts.union(Post.arel_table[:id].eq(1).or(Post.arel_table[:id].eq(2)))
81
+
82
+ expect(union.to_sql).to eq(
83
+ "SELECT \"posts\".* FROM ( SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"user_id\" = ? UNION SELECT \"posts\".* FROM \"posts\" WHERE ((\"posts\".\"id\" = 1 OR \"posts\".\"id\" = 2)) ) posts"
84
+ )
85
+ end
86
+ end
87
+ end
88
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_record_union
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Hempel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
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
+ description: UNIONs in ActiveRecord! Adds a proper union method to ActiveRecord::Relation.
98
+ email:
99
+ - plasticchicken@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".travis.yml"
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - active_record_union.gemspec
111
+ - bin/console
112
+ - lib/active_record_union.rb
113
+ - lib/active_record_union/active_record/relation/union.rb
114
+ - lib/active_record_union/version.rb
115
+ - spec/spec_helper.rb
116
+ - spec/support/models.rb
117
+ - spec/union_spec.rb
118
+ homepage: https://github.com/brianhempel/active_record_union
119
+ licenses:
120
+ - Public Domain
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.2.2
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: UNIONs in ActiveRecord! Adds a proper union method to ActiveRecord::Relation.
142
+ test_files:
143
+ - spec/spec_helper.rb
144
+ - spec/support/models.rb
145
+ - spec/union_spec.rb
146
+ - bin/console