Skip to content

Instantly share code, notes, and snippets.

@jwreagor
Created October 30, 2009 17:53
Show Gist options
  • Save jwreagor/222582 to your computer and use it in GitHub Desktop.
Save jwreagor/222582 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby -Ku
# encoding: utf-8
require 'rubygems'
require 'dm-core'
require 'pp'
module DataMapper
class Collection
def union(other)
assert_no_loaded_entries(:union)
new_collection(query.union(other.query))
end
alias | union
alias + union
def intersection(other)
assert_no_loaded_entries(:intersection)
new_collection(query.intersection(other.query))
end
alias & intersection
def difference(other)
assert_no_loaded_entries(:difference)
new_collection(query.difference(other.query))
end
alias - difference
private
def assert_no_loaded_entries(method)
unless loaded_entries.empty?
raise ArgumentError, "#{self.class}##{method} cannot be called on a loaded collection"
end
end
end
class Query
attr_accessor :conditions
def union(other)
assert_same_options(other)
query = dup
query.conditions = query.conditions.union(other.conditions)
query
end
alias | union
alias + union
def intersection(other)
assert_same_options(other)
query = dup
query.conditions = query.conditions.intersection(other.conditions)
query
end
alias & intersection
def difference(other)
assert_same_options(other)
query = dup
query.conditions = query.conditions.difference(other.conditions)
query
end
alias - difference
private
def assert_same_options(other)
# TODO: assert all the ivars, aside from @conditions, are identical
end
module Conditions
class AbstractOperation
def union(other)
Operation.new(:or, dup, other.dup)
end
alias | union
alias + union
def intersection(other)
Operation.new(:and, dup, other.dup)
end
alias & intersection
def difference(other)
Operation.new(:and, dup, Operation.new(:not, other.dup))
end
alias - difference
end
end
end
end
DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, 'sqlite3:memory:')
class Customer
include DataMapper::Resource
property :id, Serial
property :name, String
property :age, Integer
has n, :orders
end
class Order
include DataMapper::Resource
property :id, Serial
property :reference_code, String
belongs_to :customer
end
DataMapper.auto_migrate!
customer1 = Customer.create(:name => 'Dan Kubb', :age => 34)
customer2 = Customer.create(:name => 'Alex Kubb', :age => 2)
customer1.orders.create(:reference_code => 'TEST123')
customer2.orders.create(:reference_code => 'TEST321')
puts '-' * 80, 'Union:'
pp Customer.all(:name => 'Dan Kubb') | Customer.all(:name => 'Alex Kubb')
pp Customer.all(:name => 'Dan Kubb') + Customer.all(:name => 'Alex Kubb')
puts '-' * 80, 'Intersection:'
pp Customer.all(:name => 'Dan Kubb') & Customer.all(:name => 'Alex Kubb')
puts '-' * 80, 'Difference:'
pp Customer.all(:name => 'Dan Kubb') - Customer.all(:name => 'Alex Kubb')
__END__
~ (0.000258) SELECT sqlite_version(*)
~ (0.002850) DROP TABLE IF EXISTS "customers"
~ (0.001784) DROP TABLE IF EXISTS "orders"
~ (0.000038) PRAGMA table_info("customers")
~ (0.001835) CREATE TABLE "customers" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50), "age" INTEGER)
~ (0.000021) PRAGMA table_info("orders")
~ (0.002111) CREATE TABLE "orders" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "reference_code" VARCHAR(50), "customer_id" INTEGER NOT NULL)
~ (0.002192) CREATE INDEX "index_orders_customer" ON "orders" ("customer_id")
~ (0.001891) INSERT INTO "customers" ("name", "age") VALUES ('Dan Kubb', 34)
~ (0.004047) INSERT INTO "customers" ("name", "age") VALUES ('Alex Kubb', 2)
~ (0.003897) INSERT INTO "orders" ("reference_code", "customer_id") VALUES ('TEST123', 1)
~ (0.002357) INSERT INTO "orders" ("reference_code", "customer_id") VALUES ('TEST321', 2)
--------------------------------------------------------------------------------
Union:
~ (0.000104) SELECT "id", "name", "age" FROM "customers" WHERE ("name" = 'Dan Kubb' OR "name" = 'Alex Kubb') ORDER BY "id"
[#<Customer @id=1 @name="Dan Kubb" @age=34>, #<Customer @id=2 @name="Alex Kubb" @age=2>]
~ (0.000096) SELECT "id", "name", "age" FROM "customers" WHERE ("name" = 'Dan Kubb' OR "name" = 'Alex Kubb') ORDER BY "id"
[#<Customer @id=1 @name="Dan Kubb" @age=34>, #<Customer @id=2 @name="Alex Kubb" @age=2>]
--------------------------------------------------------------------------------
Intersection:
~ (0.000051) SELECT "id", "name", "age" FROM "customers" WHERE ("name" = 'Dan Kubb' AND "name" = 'Alex Kubb') ORDER BY "id"
[]
--------------------------------------------------------------------------------
Difference:
~ (0.000153) SELECT "id", "name", "age" FROM "customers" WHERE ("name" = 'Dan Kubb' AND "name" <> 'Alex Kubb') ORDER BY "id"
[#<Customer @id=1 @name="Dan Kubb" @age=34>]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment