Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 81f845af1406f5d14e4834ab31e5327c3578c090 0 parents
Jonas Nicklas jnicklas authored
18 .gitignore
@@ -0,0 +1,18 @@
+*.gem
+*.rbc
+.bundle
+.config
+.yardoc
+Gemfile.lock
+InstalledFiles
+_yardoc
+coverage
+doc/
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
+bundler_stubs
4 Gemfile
@@ -0,0 +1,4 @@
+source 'http://rubygems.org'
+
+# Specify your gem's dependencies in ar_outer_join.gemspec
+gemspec
2  Rakefile
@@ -0,0 +1,2 @@
+#!/usr/bin/env rake
+require "bundler/gem_tasks"
22 ar_outer_join.gemspec
@@ -0,0 +1,22 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/ar_outer_join/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.authors = ["Jonas Nicklas"]
+ gem.email = ["jonas.nicklas@gmail.com"]
+ gem.description = %q{TODO: Write a gem description}
+ gem.summary = %q{TODO: Write a gem summary}
+ gem.homepage = ""
+
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ gem.files = `git ls-files`.split("\n")
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ gem.name = "ar_outer_join"
+ gem.require_paths = ["lib"]
+ gem.version = ArOuterJoin::VERSION
+
+ gem.add_dependency "activerecord", "~>3.0"
+ gem.add_development_dependency "rspec"
+ gem.add_development_dependency "sqlite3"
+ gem.add_development_dependency "pry"
+end
24 lib/ar_outer_join.rb
@@ -0,0 +1,24 @@
+require "active_record"
+require "ar_outer_join/version"
+
+module ArOuterJoin
+ def outer_join(*args)
+ return self if args.compact.blank?
+
+ args.inject(self) do |scope, arg|
+ association = reflect_on_association(arg)
+
+ case association.macro
+ when :belongs_to
+ on = Arel::Nodes::On.new(arel_table[association.foreign_key].eq(association.klass.arel_table[primary_key]))
+ outer_join = Arel::Nodes::OuterJoin.new(association.klass.arel_table, on)
+ else
+ on = Arel::Nodes::On.new(association.klass.arel_table[association.foreign_key].eq(arel_table[primary_key]))
+ outer_join = Arel::Nodes::OuterJoin.new(association.klass.arel_table, on)
+ end
+ scope.joins(outer_join)
+ end
+ end
+end
+
+ActiveRecord::Base.extend ArOuterJoin
3  lib/ar_outer_join/version.rb
@@ -0,0 +1,3 @@
+module ArOuterJoin
+ VERSION = "0.0.1"
+end
51 spec/outer_join_spec.rb
@@ -0,0 +1,51 @@
+require "spec_helper"
+
+class Product < ActiveRecord::Base
+ belongs_to :category
+ belongs_to :site
+ has_many :line_items
+ has_many :baskets, :through => :line_items
+ has_many :discounts, :through => :line_items
+ has_one :user
+end
+
+class LineItem < ActiveRecord::Base
+ belongs_to :baskets
+ has_many :discounts
+end
+
+class Basket < ActiveRecord::Base; end
+class Category < ActiveRecord::Base; end
+class Site < ActiveRecord::Base; end
+class User < ActiveRecord::Base; end
+class Discount < ActiveRecord::Base; end
+
+describe ActiveRecord::Base do
+ describe ".outer_join" do
+ context "with belongs_to" do
+ it "performs an outer join" do
+ category1 = Category.create! :name => "Shoes"
+ category2 = Category.create! :name => "Shirts"
+ product1 = Product.create! :category => category1
+ product2 = Product.create! :category => category2
+ product3 = Product.create! :published => true
+ query = Product.outer_join(:category).where("categories.name = ? OR products.published = ?", "Shirts", true)
+ query.all.should =~ [product2, product3]
+ end
+ end
+
+ context "with several belongs_to" do
+ it "performs an outer join" do
+ site1 = Site.create! :name => "Elabs"
+ category1 = Category.create! :name => "Shoes"
+ category2 = Category.create! :name => "Shirts"
+ product1 = Product.create! :category => category1
+ product2 = Product.create! :category => category2
+ product3 = Product.create! :published => true
+ product4 = Product.create! :site => site1
+ query = Product.outer_join(:category, :site).where("sites.name = ? OR categories.name = ? OR products.published = ?", "Elabs", "Shirts", true)
+ query.all.should =~ [product2, product3, product4]
+ end
+ end
+ end
+end
40 spec/spec_helper.rb
@@ -0,0 +1,40 @@
+require "active_record"
+require "ar_outer_join"
+require "pry"
+
+ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
+
+ActiveRecord::Base.connection.create_table :products do |t|
+ t.integer :category_id
+ t.integer :site_id
+ t.boolean :published, :default => false, :null => false
+end
+
+ActiveRecord::Base.connection.create_table :line_items do |t|
+ t.integer :product_id
+ t.integer :basket_id
+ t.integer :discount_id
+end
+
+ActiveRecord::Base.connection.create_table :baskets
+
+ActiveRecord::Base.connection.create_table :categories do |t|
+ t.string :name
+end
+
+ActiveRecord::Base.connection.create_table :sites do |t|
+ t.string :name
+end
+
+ActiveRecord::Base.connection.create_table :discounts
+
+ActiveRecord::Base.connection.create_table :users
+
+RSpec.configure do |config|
+ config.around do |example|
+ ActiveRecord::Base.transaction do
+ example.run
+ raise ActiveRecord::Rollback
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.