Skip to content

Instantly share code, notes, and snippets.

@jswanner
Created July 18, 2012 17:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jswanner/3137608 to your computer and use it in GitHub Desktop.
Save jswanner/3137608 to your computer and use it in GitHub Desktop.
Haversine formula with Arel, with possibility of portability.
class Address < ActiveRecord::Base
def self.order_proximity_to(latitude, longitude)
order(Arel::Nodes::Haversine.new(arel_table[:latitude],
arel_table[:longitude],
latitude,
longitude))
end
end
ActiveSupport.on_load(:active_record) do
module Arel::Nodes
class Arcsine < Unary; end
class Cosine < Unary; end
class Radians < Unary; end
class Sine < Unary; end
class Sqrt < Unary; end
class Pow < InfixOperation
def initialize left, right
super(:^, left, right)
end
end
class Haversine < Unary
def initialize lat1, lng1, lat2, lng2
@expr = Multiplication.new(
Arcsine.new(
Sqrt.new(
Addition.new(
Pow.new(Sine.new(Division.new(Radians.new(lat1 - lat2), 2)), 2),
Multiplication.new(
Pow.new(Sine.new(Division.new(Radians.new(lng1 - lng2), 2)), 2),
Multiplication.new(
Cosine.new(Radians.new(lat2)),
Cosine.new(Radians.new(lat1))
)
)
)
)
), 12742
)
end
end
end
class Arel::Visitors::ToSql
private
def visit_Arel_Nodes_Haversine o
visit o.expr
end
end
class Arel::Visitors::PostgreSQL
private
def visit_Arel_Nodes_Arcsine o
"ASIN(#{visit o.expr})"
end
def visit_Arel_Nodes_Cosine o
"COS(#{visit o.expr})"
end
def visit_Arel_Nodes_Radians o
"RADIANS(#{visit o.expr})"
end
def visit_Arel_Nodes_Sine o
"SIN(#{visit o.expr})"
end
def visit_Arel_Nodes_Sqrt o
"SQRT(#{visit o.expr})"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment