AR-through-reflections in query_builder; SmqlToAR.models returns the reflections-graph; limit, offset, sub-query "()" (not sub-conditions). unstable 0.3

This commit is contained in:
Denis Knauf 2011-09-27 16:35:49 +02:00
parent 8144c72284
commit db5bbcb93a
6 changed files with 180 additions and 50 deletions

View file

@ -15,6 +15,18 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class SmqlToAR
module Assertion
def raise_unless cond, exception = nil, *args
cond, exception, *args = yield. cond, exception, *args if block_given?
raise exception || Exception, *args unless cond
end
def raise_if cond, exception = nil, *args
cond, exception, *args = yield. cond, exception, *args if block_given?
raise exception || Exception, *args if cond
end
end
include ActiveSupport::Benchmarkable
############################################################################r
# Exceptions
@ -77,12 +89,18 @@ class SmqlToAR
end
end
class OnlyOrderOnBaseError < SMQLError
class RootOnlyFunctionError < SMQLError
def initialize path
super :path => path
end
end
class ConColumnError < SMQLError
def initialize expected, got
super :expected => expected, :got => got
end
end
class BuilderError < Exception; end
#############################################################################
@ -103,7 +121,7 @@ class SmqlToAR
def initialize model, *col
@model = model
@last_model = nil
*@path, @col = Array.wrap( col).collect {|s| s.to_s.split /[.\/]/ }.flatten.collect &:to_sym
*@path, @col = Array.wrap( col).collect( &it.to_s.split( /[.\/]/)).flatten.collect( &:to_sym)
end
def last_model
@ -146,6 +164,8 @@ class SmqlToAR
exe.call pp, model
end
end
def length() @path.length+1 end
def size() @path.size+1 end
def to_a() @path+[@col] end
def to_s() to_a.join '.' end
def to_sym() to_s.to_sym end
@ -153,6 +173,7 @@ class SmqlToAR
def inspect() "#<Column: #{model} #{to_s}>" end
def relation() SmqlToAR.model_of last_model, @col end
def allowed?() ! self.protected? end
def child?() @path.empty? and !!relation end
end
attr_reader :model, :query, :conditions, :builder, :order
@ -179,6 +200,23 @@ class SmqlToAR
#p model: @model, query: @query
end
def self.models models
models = Array.wrap models
r = Hash.new {|h,k| h[k] = {} }
while model = models.tap( &:uniq!).pop
refls = model.respond_to?( :reflections) && model.reflections
refls && refls.each do |name, refl|
r[model.name][name] = case refl
when ActiveRecord::Reflection::ThroughReflection then {:macro => refl.macro, :model => refl.klass.name, :through => refl.through_reflection.name}
when ActiveRecord::Reflection::AssociationReflection then {:macro => refl.macro, :model => refl.klass.name}
else raise "Ups: #{refl.class}"
end
models.push refl.klass unless r.keys.include? refl.klass.name
end
end
r
end
def parse
benchmark 'SMQL parse' do
@conditions = ConditionTypes.try_parse @model, @query
@ -187,11 +225,11 @@ class SmqlToAR
self
end
def build
def build prefix = nil, base_table = nil
benchmark 'SMQL build query' do
@builder = QueryBuilder.new @model
@builder = QueryBuilder.new @model, prefix, base_table
table = @builder.base_table
@conditions.each {|condition| condition.build builder, table }
@conditions.each &it.build( builder, table)
end
#p builder: @builder
self