class System::FastQuery
def self.sub_join_str(model)
Util.is_submodel(model) ? " AND #{model.table_name}.#{model.inheritance_column} = '#{model.name.demodulize}'" : ""
end
class Conditions
attr_reader :conditions
def initialize(model)
@model = model
@conditions={}
end
def method_missing(method_id)
name = method_id.id2name
condition = Condition.new(@model,name.to_sym)
@conditions[name] = condition
condition
end
end
class Relation
def initialize(parent_model,child_model,belongs_to=false)
@parent_model = parent_model
@child_model = child_model
@join_model = belongs_to ? parent_model : child_model
@block_conditions = Conditions.new(@join_model)
@foreign_key = parent_model.class_name.underscore + '_id'
@model = Model.new(@join_model)
@conditions = {}
end
def model
@model
end
def and_conditions(conditions)
@conditions = conditions
self
end
def should()
yield(@block_conditions)
end
def through(key)
@foreign_key = key.to_s
self
end
def join_str
join_type = model.is_nil ? "LEFT JOIN" : "JOIN"
join = " #{join_type} #{@join_model.table_name} ON #{@parent_model.table_name}.id = #{@child_model.table_name}.#{@foreign_key} "
join << System::FastQuery.sub_join_str(@child_model)
join << System::FastQuery.sub_join_str(@parent_model)
@conditions.each do |k,v|
join << " AND #{@join_model.table_name}.#{k} = #{Util.get_value(v)}"
end
@block_conditions.conditions.each do |k,v|
join << v.to_s
end
join
end
end
class Model
attr_reader :is_nil
attr_reader :table_name
attr_reader :relations
attr_reader :model
attr_reader :conditions
def initialize(model)
@model,@table_name = model, model.table_name
@relations = {}
@is_nil = false
@conditions = []
end
def have(child_model)
unless @relations.has_key? child_model
relation = Relation.new(@model,child_model)
@relations[child_model] = relation
instance_eval("def #{child_model.name.demodulize.underscore}\n @relations[#{child_model}].model() \n end")
end
@relations[child_model]
end
def belongs_to(parent_model)
unless @relations.has_key? parent_model
relation = Relation.new(parent_model,@model,true)
@relations[parent_model] = relation
instance_eval("def #{parent_model.name.demodulize.underscore}\n @relations[#{parent_model}].model() \n end")
end
@relations[parent_model]
end
def should(attr)
operator = @conditions.empty? ? :NIL : :AND
create_condition(attr,operator)
end
def and(attr)
raise 1 if @conditions.empty?
create_condition(attr,:AND)
end
def or(attr)
raise 1 if @conditions.empty?
create_condition(attr,:OR)
end
def nil
@is_nil = true
self.should(:id).nil
end
def find_all(query_model = @model,&block)
self.find({:type=>:all,:model=>query_model},&block)
end
def find_first(query_model = @model,&block)
self.find({:type=>:first,:model=>query_model},&block)
end
def find(options={},&block)
query_model = options[:model] || @model
type = options[:type] || :all
sql = generate_sql(query_model,type)
all = query_model.find_by_sql(sql)
if block
all.find_all(&block)
end
if type == :first
all.empty? ? nil : all[0]
else
all
end
end
def order_by(order)
@order_by = " ORDER BY #{order}"
end
def generate_sql(query_model=@model,type=:all)
table = query_model.table_name
sql = "SELECT DISTINCT #{table}.* FROM #{@model.table_name}"
conditions,joins = " WHERE 1=1 ",""
generate_joins(joins,self)
generate_conditions(conditions,self)
sql << joins << conditions
sql << @order_by if @order_by
sql << " LIMIT 1 " if type == :first
sql
end
private
def create_condition(attr,operator)
condition = Condition.new(self,attr,operator)
@conditions << condition
condition
end
def generate_joins(joins,model)
model.relations.each do |k,v|
joins << v.join_str
generate_joins(joins,v.model)
end
end
def generate_conditions(conditions,model)
conditions << ' AND (' unless model.conditions.empty?
model.conditions.each_with_index do |c,i|
conditions << c.to_s
end
# conditions << System::FastQuery.sub_join_str(model.model)
conditions << ") " unless model.conditions.empty?
model.relations.each do |k,v|
generate_conditions(conditions,v.model)
end
end
end
class Condition
def initialize(model,attr,operator=:AND)
@model = model
@table_name = model.table_name
@attr = attr
@operator = operator
end
def equal(value)
internal_compare('=',value)
@model
end
def not_equal(value)
internal_compare('<>',value)
@model
end
def between(range)
@str = " #{@table_name}.#{@attr.to_s} BETWEEN #{Util.get_value(range.begin)} AND #{Util.get_value(range.end)} "
@model
end
def ==(value)
self.equal(value)
end
def <(value)
internal_compare('<',value)
end
def <=(value)
internal_compare('<=',value)
end
def >(value)
internal_compare('>',value)
end
def >=(value)
internal_compare('>=',value)
end
def like(value)
@str = " #{@table_name}.#{@attr.to_s} like '%#{value}%' "
@model
end
def in(value)
internal_in(value,"IN")
end
def not_in(value)
internal_in(value,"NOT IN")
end
def nil
@str = " #{@table_name}.#{@attr.to_s} IS NULL "
@model
end
def to_s
operator = (@operator==:NIL) ? ' ' : " #{@operator.to_s} "
operator + @str
end
private
def internal_in(value,type)
if value.empty?
if type == "IN"
@str = " 1=0 "
else
@str = " 1=1 "
end
else
@str = " #{@table_name}.#{@attr.to_s} #{type} ("
@str << value.collect{|v| Util.get_value(v)}.join(',') << ') '
end
@model
end
def internal_compare(operator,value)
@str = " #{@table_name}.#{@attr.to_s} #{operator} #{Util.get_value(value)} "
@model
end
end
end