smql 0.0.4.1 → 0.0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
 - data/lib/smql_to_ar/condition_types.rb +45 -136
 - data/lib/smql_to_ar/query_builder.rb +42 -126
 - data/lib/smql_to_ar.rb +12 -64
 - metadata +3 -3
 
    
        data/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            0.0. 
     | 
| 
      
 1 
     | 
    
         
            +
            0.0.2
         
     | 
| 
         @@ -25,44 +25,28 @@ class SmqlToAR 
     | 
|
| 
       25 
25 
     | 
    
         
             
            	# Nimmt eine Klasse ein Objekt an,  so soll diese Klasse instanziert werden.
         
     | 
| 
       26 
26 
     | 
    
         
             
            	# Alles weitere siehe Condition.
         
     | 
| 
       27 
27 
     | 
    
         
             
            	module ConditionTypes
         
     | 
| 
       28 
     | 
    
         
            -
            		extend SmqlToAR::Assertion
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
28 
     | 
    
         
             
            		class <<self
         
     | 
| 
       31 
29 
     | 
    
         
             
            			# Ex: 'givenname|surname|nick' => [:givenname, :surname, :nick]
         
     | 
| 
       32 
30 
     | 
    
         
             
            			def split_keys k
         
     | 
| 
       33 
31 
     | 
    
         
             
            				k.split( '|').collect &:to_sym
         
     | 
| 
       34 
32 
     | 
    
         
             
            			end
         
     | 
| 
       35 
33 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
            			def conditions &e
         
     | 
| 
       37 
     | 
    
         
            -
            				unless block_given?
         
     | 
| 
       38 
     | 
    
         
            -
            					r = Enumerator.new( self, :conditions)
         
     | 
| 
       39 
     | 
    
         
            -
            					s = self
         
     | 
| 
       40 
     | 
    
         
            -
            					r.define_singleton_method :[] do |k|
         
     | 
| 
       41 
     | 
    
         
            -
            						s.conditions.select {|c| c::Operator === k }
         
     | 
| 
       42 
     | 
    
         
            -
            					end
         
     | 
| 
       43 
     | 
    
         
            -
            					return r
         
     | 
| 
       44 
     | 
    
         
            -
            				end
         
     | 
| 
       45 
     | 
    
         
            -
            				constants.each do |c|
         
     | 
| 
       46 
     | 
    
         
            -
            					next  if :Condition == c
         
     | 
| 
       47 
     | 
    
         
            -
            					c = const_get c
         
     | 
| 
       48 
     | 
    
         
            -
            					next  if Condition === c
         
     | 
| 
       49 
     | 
    
         
            -
            					yield c
         
     | 
| 
       50 
     | 
    
         
            -
            				end
         
     | 
| 
       51 
     | 
    
         
            -
            			end
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
34 
     | 
    
         
             
            			# Eine Regel parsen.
         
     | 
| 
       54 
35 
     | 
    
         
             
            			# Ex: Person, "givenname=", "Peter"
         
     | 
| 
       55 
36 
     | 
    
         
             
            			def try_parse_it model, colop, val
         
     | 
| 
       56 
37 
     | 
    
         
             
            				r = nil
         
     | 
| 
       57 
38 
     | 
    
         
             
            				#p :try_parse => { :model => model, :colop => colop, :value => val }
         
     | 
| 
       58 
     | 
    
         
            -
            				 
     | 
| 
       59 
     | 
    
         
            -
            					 
     | 
| 
      
 39 
     | 
    
         
            +
            				constants.each do |c|
         
     | 
| 
      
 40 
     | 
    
         
            +
            					next  if :Condition == c
         
     | 
| 
      
 41 
     | 
    
         
            +
            					c = const_get c
         
     | 
| 
      
 42 
     | 
    
         
            +
            					next  if Condition === c
         
     | 
| 
      
 43 
     | 
    
         
            +
            					raise UnexpectedColOpError.new( model, colop, val)  unless colop =~ /^(?:\d*:)?(.*?)(\W*)$/
         
     | 
| 
       60 
44 
     | 
    
         
             
            					col, op = $1, $2
         
     | 
| 
       61 
45 
     | 
    
         
             
            					col = split_keys( col).collect {|c| Column.new model, c }
         
     | 
| 
       62 
46 
     | 
    
         
             
            					r = c.try_parse model, col, op, val
         
     | 
| 
       63 
47 
     | 
    
         
             
            					break  if r
         
     | 
| 
       64 
48 
     | 
    
         
             
            				end
         
     | 
| 
       65 
     | 
    
         
            -
            				 
     | 
| 
      
 49 
     | 
    
         
            +
            				raise UnexpectedError.new( model, colop, val)  unless r
         
     | 
| 
       66 
50 
     | 
    
         
             
            				r
         
     | 
| 
       67 
51 
     | 
    
         
             
            			end
         
     | 
| 
       68 
52 
     | 
    
         | 
| 
         @@ -88,24 +72,16 @@ class SmqlToAR 
     | 
|
| 
       88 
72 
     | 
    
         
             
            		end
         
     | 
| 
       89 
73 
     | 
    
         | 
| 
       90 
74 
     | 
    
         
             
            		class Condition
         
     | 
| 
       91 
     | 
    
         
            -
            			include SmqlToAR::Assertion
         
     | 
| 
       92 
     | 
    
         
            -
            			extend SmqlToAR::Assertion
         
     | 
| 
       93 
75 
     | 
    
         
             
            			attr_reader :value, :cols
         
     | 
| 
       94 
76 
     | 
    
         
             
            			Operator = nil
         
     | 
| 
       95 
77 
     | 
    
         
             
            			Expected = []
         
     | 
| 
       96 
78 
     | 
    
         
             
            			Where = nil
         
     | 
| 
       97 
79 
     | 
    
         | 
| 
       98 
     | 
    
         
            -
            			 
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
            				 
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
            					new model, cols, val  if self::Operator === op and self::Expected.any?( &it === val)
         
     | 
| 
       104 
     | 
    
         
            -
            				end
         
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
            				def inspect
         
     | 
| 
       107 
     | 
    
         
            -
            					"#{self.name}(:operator=>#{self::Operator.inspect}, :expected=>#{self::Expected.inspect}, :where=>#{self::Where.inspect})"
         
     | 
| 
       108 
     | 
    
         
            -
            				end
         
     | 
| 
      
 80 
     | 
    
         
            +
            			# Versuche das Objekt zu erkennen.  Operator und Expected muessen passen.
         
     | 
| 
      
 81 
     | 
    
         
            +
            			# Passt das Object,  die Klasse instanzieren.
         
     | 
| 
      
 82 
     | 
    
         
            +
            			def self.try_parse model, cols, op, val
         
     | 
| 
      
 83 
     | 
    
         
            +
            				#p :self => name, :try_parse => op, :cols => cols, :with => self::Operator, :value => val, :expected => self::Expected, :model => model.name
         
     | 
| 
      
 84 
     | 
    
         
            +
            				new model, cols, val  if self::Operator === op and self::Expected.any? {|i| i === val }
         
     | 
| 
       109 
85 
     | 
    
         
             
            			end
         
     | 
| 
       110 
86 
     | 
    
         | 
| 
       111 
87 
     | 
    
         
             
            			def initialize model, cols, val
         
     | 
| 
         @@ -117,10 +93,6 @@ class SmqlToAR 
     | 
|
| 
       117 
93 
     | 
    
         
             
            				verify
         
     | 
| 
       118 
94 
     | 
    
         
             
            			end
         
     | 
| 
       119 
95 
     | 
    
         | 
| 
       120 
     | 
    
         
            -
            			def inspect
         
     | 
| 
       121 
     | 
    
         
            -
            				"#<#{self.class.name}:0x#{(self.object_id<<1).to_s 16} model: #{self.class.name}, cols: #{@cols.inspect}, value: #{@value.inspect}>"
         
     | 
| 
       122 
     | 
    
         
            -
            			end
         
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
96 
     | 
    
         
             
            			def verify
         
     | 
| 
       125 
97 
     | 
    
         
             
            				@cols.each do |col|
         
     | 
| 
       126 
98 
     | 
    
         
             
            					verify_column col
         
     | 
| 
         @@ -131,19 +103,19 @@ class SmqlToAR 
     | 
|
| 
       131 
103 
     | 
    
         
             
            			# Gibt es eine Spalte diesen Namens?
         
     | 
| 
       132 
104 
     | 
    
         
             
            			# Oder:  Gibt es eine Relation diesen Namens?  (Hier nicht der Fall)
         
     | 
| 
       133 
105 
     | 
    
         
             
            			def verify_column col
         
     | 
| 
       134 
     | 
    
         
            -
            				 
     | 
| 
      
 106 
     | 
    
         
            +
            				raise NonExistingColumnError.new( %w[Column], col)  unless col.exist_in?
         
     | 
| 
       135 
107 
     | 
    
         
             
            			end
         
     | 
| 
       136 
108 
     | 
    
         | 
| 
       137 
109 
     | 
    
         
             
            			# Modelle koennen Spalten/Relationen verbieten mit Model#smql_protected.
         
     | 
| 
       138 
110 
     | 
    
         
             
            			# Dieses muss ein Object mit #include?( name_als_string) zurueckliefern,
         
     | 
| 
       139 
111 
     | 
    
         
             
            			# welches true fuer verboten und false fuer, erlaubt steht.
         
     | 
| 
       140 
112 
     | 
    
         
             
            			def verify_allowed col
         
     | 
| 
       141 
     | 
    
         
            -
            				 
     | 
| 
      
 113 
     | 
    
         
            +
            				raise ProtectedColumnError.new( col)  if col.protected?
         
     | 
| 
       142 
114 
     | 
    
         
             
            			end
         
     | 
| 
       143 
115 
     | 
    
         | 
| 
       144 
116 
     | 
    
         
             
            			# Erstelle alle noetigen Klauseln. builder nimmt diese entgegen,
         
     | 
| 
       145 
     | 
    
         
            -
            			# wobei builder. 
     | 
| 
       146 
     | 
    
         
            -
            			# mehrere Schluessel bedeuten, dass die Values _alle_ zutreffen muessen, wobei die Schluessel  
     | 
| 
      
 117 
     | 
    
         
            +
            			# wobei builder.join, builder.select, builder.where und builder.wobs von interesse sind.
         
     | 
| 
      
 118 
     | 
    
         
            +
            			# mehrere Schluessel bedeuten, dass die Values _alle_ zutreffen muessen, wobei die Schluessel geodert werden.
         
     | 
| 
       147 
119 
     | 
    
         
             
            			# Ex:
         
     | 
| 
       148 
120 
     | 
    
         
             
            			# 1) {"givenname=", "Peter"} #=> givenname = 'Peter'
         
     | 
| 
       149 
121 
     | 
    
         
             
            			# 2) {"givenname=", ["Peter", "Hans"]} #=> ( givenname = 'Peter' OR givenname = 'Hans' )
         
     | 
| 
         @@ -156,16 +128,15 @@ class SmqlToAR 
     | 
|
| 
       156 
128 
     | 
    
         
             
            					@cols.each do |col|
         
     | 
| 
       157 
129 
     | 
    
         
             
            						col.joins builder, table
         
     | 
| 
       158 
130 
     | 
    
         
             
            						col = builder.column table+col.path, col.col
         
     | 
| 
       159 
     | 
    
         
            -
            						builder.where values.keys.collect {|vid| self.class::Where % [ col, vid.to_s ] }
         
     | 
| 
      
 131 
     | 
    
         
            +
            						builder.where *values.keys.collect {|vid| self.class::Where % [ col, vid.to_s ] }
         
     | 
| 
       160 
132 
     | 
    
         
             
            					end
         
     | 
| 
       161 
133 
     | 
    
         
             
            				else
         
     | 
| 
       162 
     | 
    
         
            -
            					b2 = SmqlToAR::And.new builder
         
     | 
| 
       163 
134 
     | 
    
         
             
            					values.keys.each do |vid|
         
     | 
| 
       164 
     | 
    
         
            -
            						 
     | 
| 
      
 135 
     | 
    
         
            +
            						builder.where *@cols.collect {|col|
         
     | 
| 
       165 
136 
     | 
    
         
             
            								col.joins builder, table
         
     | 
| 
       166 
137 
     | 
    
         
             
            								col = builder.column table+col.path, col.col
         
     | 
| 
       167 
138 
     | 
    
         
             
            								self.class::Where % [ col, vid.to_s ]
         
     | 
| 
       168 
     | 
    
         
            -
            							} 
     | 
| 
      
 139 
     | 
    
         
            +
            							}
         
     | 
| 
       169 
140 
     | 
    
         
             
            					end
         
     | 
| 
       170 
141 
     | 
    
         
             
            				end
         
     | 
| 
       171 
142 
     | 
    
         
             
            				self
         
     | 
| 
         @@ -214,92 +185,50 @@ class SmqlToAR 
     | 
|
| 
       214 
185 
     | 
    
         | 
| 
       215 
186 
     | 
    
         
             
            		In = simple_condition NotIn, '|=', '%s IN (%s)', [Array]
         
     | 
| 
       216 
187 
     | 
    
         
             
            		In2 = simple_condition In, '', nil, [Array]
         
     | 
| 
       217 
     | 
    
         
            -
            		NotEqual = simple_condition Condition,  
     | 
| 
       218 
     | 
    
         
            -
            		NotEqual2 = simple_condition Condition, '<>', "%s <> %s", [Array, String, Numeric]
         
     | 
| 
      
 188 
     | 
    
         
            +
            		NotEqual = simple_condition Condition, /\!=|<>/, "%s <> %s", [Array, String, Numeric]
         
     | 
| 
       219 
189 
     | 
    
         
             
            		GreaterThanOrEqual = simple_condition Condition, '>=', "%s >= %s", [Array, Numeric]
         
     | 
| 
       220 
190 
     | 
    
         
             
            		LesserThanOrEqual = simple_condition Condition, '<=', "%s <= %s", [Array, Numeric]
         
     | 
| 
       221 
     | 
    
         
            -
             
     | 
| 
       222 
     | 
    
         
            -
            		# Examples:
         
     | 
| 
       223 
     | 
    
         
            -
            		# { 'articles=>' => { id: 1 } }
         
     | 
| 
       224 
     | 
    
         
            -
            		# { 'articles=>' => [ { id: 1 }, { id: 2 } ] }
         
     | 
| 
       225 
191 
     | 
    
         
             
            		class EqualJoin <Condition
         
     | 
| 
       226 
     | 
    
         
            -
            			Operator = ' 
     | 
| 
       227 
     | 
    
         
            -
            			Expected = [Hash 
     | 
| 
      
 192 
     | 
    
         
            +
            			Operator = '='
         
     | 
| 
      
 193 
     | 
    
         
            +
            			Expected = [Hash]
         
     | 
| 
       228 
194 
     | 
    
         | 
| 
       229 
195 
     | 
    
         
             
            			def initialize *pars
         
     | 
| 
       230 
196 
     | 
    
         
             
            				super( *pars)
         
     | 
| 
       231 
     | 
    
         
            -
            				@value = Array.wrap @value
         
     | 
| 
       232 
197 
     | 
    
         
             
            				cols = {}
         
     | 
| 
       233 
198 
     | 
    
         
             
            				@cols.each do |col|
         
     | 
| 
       234 
     | 
    
         
            -
            					col_model = col. 
     | 
| 
       235 
     | 
    
         
            -
            					 
     | 
| 
      
 199 
     | 
    
         
            +
            					col_model = SmqlToAR.model_of col.last_model, col.col
         
     | 
| 
      
 200 
     | 
    
         
            +
            					#p col_model: col_model.to_s, value: @value
         
     | 
| 
      
 201 
     | 
    
         
            +
            					cols[col] = [col_model] + ConditionTypes.try_parse( col_model, @value)
         
     | 
| 
       236 
202 
     | 
    
         
             
            				end
         
     | 
| 
       237 
203 
     | 
    
         
             
            				@cols = cols
         
     | 
| 
       238 
204 
     | 
    
         
             
            			end
         
     | 
| 
       239 
205 
     | 
    
         | 
| 
       240 
206 
     | 
    
         
             
            			def verify_column col
         
     | 
| 
       241 
     | 
    
         
            -
            				 
     | 
| 
      
 207 
     | 
    
         
            +
            				refl = SmqlToAR.model_of col.last_model, col.col
         
     | 
| 
      
 208 
     | 
    
         
            +
            				#p refl: refl, model: @model.name, col: col, :reflections => @model.reflections.keys
         
     | 
| 
      
 209 
     | 
    
         
            +
            				raise NonExistingRelationError.new( %w[Relation], col)  unless refl
         
     | 
| 
       242 
210 
     | 
    
         
             
            			end
         
     | 
| 
       243 
211 
     | 
    
         | 
| 
       244 
212 
     | 
    
         
             
            			def build builder, table
         
     | 
| 
       245 
213 
     | 
    
         
             
            				@cols.each do |col, sub|
         
     | 
| 
       246 
     | 
    
         
            -
            					model, *sub = sub
         
     | 
| 
       247 
214 
     | 
    
         
             
            					t = table + col.path + [col.col]
         
     | 
| 
       248 
     | 
    
         
            -
            					 
     | 
| 
       249 
     | 
    
         
            -
            					 
     | 
| 
       250 
     | 
    
         
            -
            					 
     | 
| 
       251 
     | 
    
         
            -
            					 
     | 
| 
       252 
     | 
    
         
            -
             
     | 
| 
       253 
     | 
    
         
            -
            				self
         
     | 
| 
       254 
     | 
    
         
            -
            			end
         
     | 
| 
       255 
     | 
    
         
            -
            		end
         
     | 
| 
       256 
     | 
    
         
            -
             
     | 
| 
       257 
     | 
    
         
            -
            		# Takes to Queries.
         
     | 
| 
       258 
     | 
    
         
            -
            		# First Query will be a Subquery, second a regular query.
         
     | 
| 
       259 
     | 
    
         
            -
            		# Example:
         
     | 
| 
       260 
     | 
    
         
            -
            		#   Person.smql 'sub.articles:' => [{'limit:' => 1, 'order:': 'updated_at desc'}, {'content~' => 'some text'}]
         
     | 
| 
       261 
     | 
    
         
            -
            		# Person must have as last Article (compared by updated_at) owned by Person a Artive which has 'some text' in content.
         
     | 
| 
       262 
     | 
    
         
            -
            		# The last Article needn't to have 'some text' has content,  the subquery takes it anyway.
         
     | 
| 
       263 
     | 
    
         
            -
            		# But the second query compares to it and never to any other Article,  because these are filtered by first query.
         
     | 
| 
       264 
     | 
    
         
            -
            		# The difference to
         
     | 
| 
       265 
     | 
    
         
            -
            		#   Person.smql :articles => {'content~' => 'some text', 'limit:' => 1, 'order:': 'updated_at desc'}
         
     | 
| 
       266 
     | 
    
         
            -
            		# is,  second is not allowed (limit and order must be in root) and this means something like
         
     | 
| 
       267 
     | 
    
         
            -
            		#   "Person must have the Article owned by Person which has 'some text' in content.
         
     | 
| 
       268 
     | 
    
         
            -
            		#   limit and order has no function in this query and this article needn't to be the last."
         
     | 
| 
       269 
     | 
    
         
            -
            		class SubEqualJoin < EqualJoin
         
     | 
| 
       270 
     | 
    
         
            -
            			Operator = '()'
         
     | 
| 
       271 
     | 
    
         
            -
            			Expected = [lambda {|x| x.kind_of?( Array) and (1..2).include?( x.length) and x.all?( &it.kind_of?( Hash))}]
         
     | 
| 
       272 
     | 
    
         
            -
             
     | 
| 
       273 
     | 
    
         
            -
            			def initialize model, cols, val
         
     | 
| 
       274 
     | 
    
         
            -
            				super model, cols, val[1]
         
     | 
| 
       275 
     | 
    
         
            -
            				# sub: model, subquery, sub(condition)
         
     | 
| 
       276 
     | 
    
         
            -
            				@cols.each {|col, sub| sub[ 1..-1] = SmqlToAR.new( col.relation, val[0]).parse, *sub[-1] }
         
     | 
| 
       277 
     | 
    
         
            -
            			end
         
     | 
| 
       278 
     | 
    
         
            -
             
     | 
| 
       279 
     | 
    
         
            -
            			def verify_column col
         
     | 
| 
       280 
     | 
    
         
            -
            				raise_unless col.child?, ConColumnError.new( [:Column], col)
         
     | 
| 
       281 
     | 
    
         
            -
            			end
         
     | 
| 
       282 
     | 
    
         
            -
             
     | 
| 
       283 
     | 
    
         
            -
            			def build builder, table
         
     | 
| 
       284 
     | 
    
         
            -
            				@cols.each do |col, sub|
         
     | 
| 
       285 
     | 
    
         
            -
            					t = table+col.to_a
         
     | 
| 
       286 
     | 
    
         
            -
            					builder.sub_joins t, col, *sub[0..1]
         
     | 
| 
       287 
     | 
    
         
            -
            					#ap sub: sub[2..-1]
         
     | 
| 
       288 
     | 
    
         
            -
            					sub[2..-1].each &it.build( builder, t)
         
     | 
| 
      
 215 
     | 
    
         
            +
            					#p sub: sub
         
     | 
| 
      
 216 
     | 
    
         
            +
            					p col: col, joins: col.joins
         
     | 
| 
      
 217 
     | 
    
         
            +
            					col.joins.each {|j, m| builder.join table+j, m }
         
     | 
| 
      
 218 
     | 
    
         
            +
            					builder.join t, SmqlToAR.model_of( col.last_model, col.col)
         
     | 
| 
      
 219 
     | 
    
         
            +
            					sub[1..-1].each {|one| one.build builder, t }
         
     | 
| 
       289 
220 
     | 
    
         
             
            				end
         
     | 
| 
       290 
221 
     | 
    
         
             
            				self
         
     | 
| 
       291 
222 
     | 
    
         
             
            			end
         
     | 
| 
       292 
223 
     | 
    
         
             
            		end
         
     | 
| 
       293 
     | 
    
         
            -
             
     | 
| 
       294 
224 
     | 
    
         
             
            		Equal = simple_condition Condition, '=', "%s = %s", [Array, String, Numeric]
         
     | 
| 
       295 
225 
     | 
    
         
             
            		Equal2 = simple_condition Equal, '', "%s = %s", [String, Numeric]
         
     | 
| 
       296 
226 
     | 
    
         
             
            		GreaterThan = simple_condition Condition, '>', "%s > %s", [Array, Numeric]
         
     | 
| 
       297 
227 
     | 
    
         
             
            		LesserThan = simple_condition Condition, '<', "%s < %s", [Array, Numeric]
         
     | 
| 
       298 
228 
     | 
    
         
             
            		NotIlike = simple_condition Condition, '!~', "%s NOT ILIKE %s", [Array, String]
         
     | 
| 
       299 
229 
     | 
    
         
             
            		Ilike = simple_condition Condition, '~', "%s ILIKE %s", [Array, String]
         
     | 
| 
       300 
     | 
    
         
            -
            		Exists = simple_condition Condition, '', '%s IS NOT NULL', [true]
         
     | 
| 
       301 
     | 
    
         
            -
            		NotExists = simple_condition Condition, '', '%s IS NULL', [false]
         
     | 
| 
       302 
230 
     | 
    
         | 
| 
      
 231 
     | 
    
         
            +
            		####### No Operator #######
         
     | 
| 
       303 
232 
     | 
    
         
             
            		Join = simple_condition EqualJoin, '', nil, [Hash]
         
     | 
| 
       304 
233 
     | 
    
         
             
            		InRange2 = simple_condition InRange, '', nil, [Range]
         
     | 
| 
       305 
234 
     | 
    
         
             
            		class Select < Condition
         
     | 
| 
         @@ -307,7 +236,7 @@ class SmqlToAR 
     | 
|
| 
       307 
236 
     | 
    
         
             
            			Expected = [nil]
         
     | 
| 
       308 
237 
     | 
    
         | 
| 
       309 
238 
     | 
    
         
             
            			def verify_column col
         
     | 
| 
       310 
     | 
    
         
            -
            				 
     | 
| 
      
 239 
     | 
    
         
            +
            				raise NonExistingSelectableError.new( col)  unless col.exist_in? or SmqlToAR.model_of( col.last_model, col.col)
         
     | 
| 
       311 
240 
     | 
    
         
             
            			end
         
     | 
| 
       312 
241 
     | 
    
         | 
| 
       313 
242 
     | 
    
         
             
            			def build builder, table
         
     | 
| 
         @@ -329,19 +258,13 @@ class SmqlToAR 
     | 
|
| 
       329 
258 
     | 
    
         
             
            			Expected = [String, Array, Hash, Numeric, nil]
         
     | 
| 
       330 
259 
     | 
    
         | 
| 
       331 
260 
     | 
    
         
             
            			class Function
         
     | 
| 
       332 
     | 
    
         
            -
            				include SmqlToAR::Assertion
         
     | 
| 
       333 
261 
     | 
    
         
             
            				Name = nil
         
     | 
| 
       334 
262 
     | 
    
         
             
            				Expected = []
         
     | 
| 
       335 
263 
     | 
    
         
             
            				attr_reader :model, :func, :args
         
     | 
| 
       336 
264 
     | 
    
         | 
| 
       337 
     | 
    
         
            -
            				 
     | 
| 
       338 
     | 
    
         
            -
            					 
     | 
| 
       339 
     | 
    
         
            -
             
     | 
| 
       340 
     | 
    
         
            -
            					end
         
     | 
| 
       341 
     | 
    
         
            -
             
     | 
| 
       342 
     | 
    
         
            -
            					def inspect
         
     | 
| 
       343 
     | 
    
         
            -
            						"#{self.name}(:name=>#{self::Name}, :expected=>#{self::Expected})"
         
     | 
| 
       344 
     | 
    
         
            -
            					end
         
     | 
| 
      
 265 
     | 
    
         
            +
            				def self.try_parse model, func, args
         
     | 
| 
      
 266 
     | 
    
         
            +
            					SmqlToAR.logger.info( { try_parse: [func,args]}.inspect)
         
     | 
| 
      
 267 
     | 
    
         
            +
            					self.new model, func, args  if self::Name === func and self::Expected.any? {|e| e === args }
         
     | 
| 
       345 
268 
     | 
    
         
             
            				end
         
     | 
| 
       346 
269 
     | 
    
         | 
| 
       347 
270 
     | 
    
         
             
            				def initialize model, func, args
         
     | 
| 
         @@ -354,19 +277,22 @@ class SmqlToAR 
     | 
|
| 
       354 
277 
     | 
    
         
             
            				Expected = [String, Array, Hash, nil]
         
     | 
| 
       355 
278 
     | 
    
         | 
| 
       356 
279 
     | 
    
         
             
            				def initialize model, func, args
         
     | 
| 
      
 280 
     | 
    
         
            +
            					SmqlToAR.logger.info( {args: args}.inspect)
         
     | 
| 
       357 
281 
     | 
    
         
             
            					args = case args
         
     | 
| 
       358 
282 
     | 
    
         
             
            						when String then [args]
         
     | 
| 
       359 
283 
     | 
    
         
             
            						when Array, Hash then args.to_a
         
     | 
| 
       360 
284 
     | 
    
         
             
            						when nil then nil
         
     | 
| 
       361 
285 
     | 
    
         
             
            						else raise 'Oops'
         
     | 
| 
       362 
286 
     | 
    
         
             
            						end
         
     | 
| 
      
 287 
     | 
    
         
            +
            					SmqlToAR.logger.info( {args: args}.inspect)
         
     | 
| 
       363 
288 
     | 
    
         
             
            					args.andand.collect! do |o|
         
     | 
| 
       364 
289 
     | 
    
         
             
            						o = Array.wrap o
         
     | 
| 
       365 
290 
     | 
    
         
             
            						col = Column.new model, o.first
         
     | 
| 
       366 
291 
     | 
    
         
             
            						o = 'desc' == o.last.to_s.downcase ? :DESC : :ASC
         
     | 
| 
       367 
     | 
    
         
            -
            						 
     | 
| 
      
 292 
     | 
    
         
            +
            						raise NonExistingColumnError.new( [:Column], col)  unless col.exist_in?
         
     | 
| 
       368 
293 
     | 
    
         
             
            						[col, o]
         
     | 
| 
       369 
294 
     | 
    
         
             
            					end
         
     | 
| 
      
 295 
     | 
    
         
            +
            					SmqlToAR.logger.info( {args: args}.inspect)
         
     | 
| 
       370 
296 
     | 
    
         
             
            					super model, func, args
         
     | 
| 
       371 
297 
     | 
    
         
             
            				end
         
     | 
| 
       372 
298 
     | 
    
         | 
| 
         @@ -376,39 +302,22 @@ class SmqlToAR 
     | 
|
| 
       376 
302 
     | 
    
         
             
            						col, o = o
         
     | 
| 
       377 
303 
     | 
    
         
             
            						col.joins builder, table
         
     | 
| 
       378 
304 
     | 
    
         
             
            						t = table + col.path
         
     | 
| 
       379 
     | 
    
         
            -
            						 
     | 
| 
      
 305 
     | 
    
         
            +
            						#raise OnlyOrderOnBaseError.new( t)  unless 1 == t.length
         
     | 
| 
       380 
306 
     | 
    
         
             
            						builder.order t, col.col, o
         
     | 
| 
       381 
307 
     | 
    
         
             
            					end
         
     | 
| 
       382 
308 
     | 
    
         
             
            				end
         
     | 
| 
       383 
309 
     | 
    
         
             
            			end
         
     | 
| 
       384 
310 
     | 
    
         | 
| 
       385 
     | 
    
         
            -
            			class Limit < Function
         
     | 
| 
       386 
     | 
    
         
            -
            				Name = :limit
         
     | 
| 
       387 
     | 
    
         
            -
            				Expected = [Fixnum]
         
     | 
| 
       388 
     | 
    
         
            -
             
     | 
| 
       389 
     | 
    
         
            -
            				def build builder, table
         
     | 
| 
       390 
     | 
    
         
            -
            					raise_unless 1 == table.length, RootOnlyFunctionError.new( table)
         
     | 
| 
       391 
     | 
    
         
            -
            					builder.limit = Array.wrap(@args).first.to_i
         
     | 
| 
       392 
     | 
    
         
            -
            				end
         
     | 
| 
       393 
     | 
    
         
            -
            			end
         
     | 
| 
       394 
     | 
    
         
            -
             
     | 
| 
       395 
     | 
    
         
            -
            			class Offset < Function
         
     | 
| 
       396 
     | 
    
         
            -
            				Name = :offset
         
     | 
| 
       397 
     | 
    
         
            -
            				Expected = [Fixnum]
         
     | 
| 
       398 
     | 
    
         
            -
             
     | 
| 
       399 
     | 
    
         
            -
            				def build builder, table
         
     | 
| 
       400 
     | 
    
         
            -
            					raise_unless 1 == table.length, RootOnlyFunctionError.new( table)
         
     | 
| 
       401 
     | 
    
         
            -
            					builder.offset = Array.wrap(@args).first.to_i
         
     | 
| 
       402 
     | 
    
         
            -
            				end
         
     | 
| 
       403 
     | 
    
         
            -
            			end
         
     | 
| 
       404 
     | 
    
         
            -
             
     | 
| 
       405 
311 
     | 
    
         
             
            			def self.new model, col, val
         
     | 
| 
      
 312 
     | 
    
         
            +
            				SmqlToAR.logger.info( { function: col.first.to_sym }.inspect)
         
     | 
| 
       406 
313 
     | 
    
         
             
            				r = nil
         
     | 
| 
       407 
314 
     | 
    
         
             
            				constants.each do |c|
         
     | 
| 
       408 
315 
     | 
    
         
             
            					next  if [:Function, :Where, :Expected, :Operator].include? c
         
     | 
| 
       409 
316 
     | 
    
         
             
            					c = const_get c
         
     | 
| 
       410 
317 
     | 
    
         
             
            					next  if Function === c or not c.respond_to?( :try_parse)
         
     | 
| 
      
 318 
     | 
    
         
            +
            					SmqlToAR.logger.info( {f: c}.inspect)
         
     | 
| 
       411 
319 
     | 
    
         
             
            					r = c.try_parse model, col.first.to_sym, val
         
     | 
| 
      
 320 
     | 
    
         
            +
            					SmqlToAR.logger.info( {r: r}.inspect)
         
     | 
| 
       412 
321 
     | 
    
         
             
            					break  if r
         
     | 
| 
       413 
322 
     | 
    
         
             
            				end
         
     | 
| 
       414 
323 
     | 
    
         
             
            				r
         
     | 
| 
         @@ -22,41 +22,36 @@ class SmqlToAR 
     | 
|
| 
       22 
22 
     | 
    
         
             
            		class Vid
         
     | 
| 
       23 
23 
     | 
    
         
             
            			attr_reader :vid
         
     | 
| 
       24 
24 
     | 
    
         
             
            			def initialize( vid)  @vid = vid  end
         
     | 
| 
       25 
     | 
    
         
            -
            			def to_s() ": 
     | 
| 
       26 
     | 
    
         
            -
            			def to_sym() " 
     | 
| 
      
 25 
     | 
    
         
            +
            			def to_s() ":c#{@vid}" end
         
     | 
| 
      
 26 
     | 
    
         
            +
            			def to_sym() "c#{@vid}".to_sym end
         
     | 
| 
       27 
27 
     | 
    
         
             
            			alias sym to_sym
         
     | 
| 
       28 
28 
     | 
    
         
             
            			def to_i()  @vid  end
         
     | 
| 
       29 
29 
     | 
    
         
             
            		end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
            		attr_reader :table_alias, :model, :table_model, :base_table, :_where, :_select, :_wobs, :_joins 
     | 
| 
       32 
     | 
    
         
            -
            		attr_accessor :logger 
     | 
| 
      
 31 
     | 
    
         
            +
            		attr_reader :table_alias, :model, :table_model, :base_table, :_where, :_select, :_wobs, :_joins
         
     | 
| 
      
 32 
     | 
    
         
            +
            		attr_accessor :logger
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
            		def initialize model 
     | 
| 
       35 
     | 
    
         
            -
            			@prefix = "smql"
         
     | 
| 
      
 34 
     | 
    
         
            +
            		def initialize model
         
     | 
| 
       36 
35 
     | 
    
         
             
            			@logger = SmqlToAR.logger
         
     | 
| 
       37 
36 
     | 
    
         
             
            			@table_alias = Hash.new do |h, k|
         
     | 
| 
       38 
     | 
    
         
            -
            				 
     | 
| 
       39 
     | 
    
         
            -
            				h[k] =  
     | 
| 
      
 37 
     | 
    
         
            +
            				k = Array.wrap k
         
     | 
| 
      
 38 
     | 
    
         
            +
            				h[k] = "smql,#{k.join(',')}"
         
     | 
| 
       40 
39 
     | 
    
         
             
            			end
         
     | 
| 
       41 
     | 
    
         
            -
            			@_vid, @_where, @_wobs, @model, @quoter = 0,  
     | 
| 
      
 40 
     | 
    
         
            +
            			@_vid, @_where, @_wobs, @model, @quoter = 0, [], {}, model, model.connection
         
     | 
| 
       42 
41 
     | 
    
         
             
            			@base_table = [model.table_name.to_sym]
         
     | 
| 
       43 
42 
     | 
    
         
             
            			@table_alias[ @base_table] = @base_table.first
         
     | 
| 
       44 
43 
     | 
    
         
             
            			t = quote_table_name @table_alias[ @base_table]
         
     | 
| 
       45 
     | 
    
         
            -
            			@_select, @_joins, @_joined, @_includes, @_order = ["DISTINCT #{t}.*"], "", [ 
     | 
| 
      
 44 
     | 
    
         
            +
            			@_select, @_joins, @_joined, @_includes, @_order = ["DISTINCT #{t}.*"], "", [], [], []
         
     | 
| 
       46 
45 
     | 
    
         
             
            			@table_model = {@base_table => @model}
         
     | 
| 
       47 
46 
     | 
    
         
             
            		end
         
     | 
| 
       48 
47 
     | 
    
         | 
| 
       49 
48 
     | 
    
         
             
            		def vid()  Vid.new( @_vid+=1)  end
         
     | 
| 
       50 
49 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
            		def inspect
         
     | 
| 
       52 
     | 
    
         
            -
            			"#<#{self.class.name}:#{"0x%x"% (self.object_id<<1)}|#{@prefix}:#{@base_table}:#{@model} vid=#{@_vid} where=#{@_where} wobs=#{@_wobs} select=#{@_select} aliases=#{@_table_alias}>"
         
     | 
| 
       53 
     | 
    
         
            -
            		end
         
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
50 
     | 
    
         
             
            		# Jede via where uebergebene Condition wird geodert und alle zusammen werden geundet.
         
     | 
| 
       56 
51 
     | 
    
         
             
            		# "Konjunktive Normalform".  Allerdings duerfen Conditions auch Komplexe Abfragen enthalten.
         
     | 
| 
       57 
     | 
    
         
            -
            		# Ex: builder.where(  
     | 
| 
      
 52 
     | 
    
         
            +
            		# Ex: builder.where( 'a = a', 'b = c').where( 'c = d', 'e = e').where( 'x = y').where( '( m = n AND o = p )', 'f = g')
         
     | 
| 
       58 
53 
     | 
    
         
             
            		#        #=> WHERE ( a = a OR b = c ) AND ( c = d OR e = e ) AND x = y ( ( m = n AND o = p ) OR f = g )
         
     | 
| 
       59 
     | 
    
         
            -
            		def where cond
         
     | 
| 
      
 54 
     | 
    
         
            +
            		def where *cond
         
     | 
| 
       60 
55 
     | 
    
         
             
            			@_where.push cond
         
     | 
| 
       61 
56 
     | 
    
         
             
            			self
         
     | 
| 
       62 
57 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -79,52 +74,30 @@ class SmqlToAR 
     | 
|
| 
       79 
74 
     | 
    
         
             
            		end
         
     | 
| 
       80 
75 
     | 
    
         | 
| 
       81 
76 
     | 
    
         
             
            		def build_join orig, pretable, table, prekey, key
         
     | 
| 
       82 
     | 
    
         
            -
            			"  
     | 
| 
      
 77 
     | 
    
         
            +
            			" JOIN #{quote_table_name orig.to_sym} AS #{quote_table_name table} ON #{column pretable, prekey} = #{column table, key} "
         
     | 
| 
       83 
78 
     | 
    
         
             
            		end
         
     | 
| 
       84 
79 
     | 
    
         | 
| 
       85 
     | 
    
         
            -
            		def  
     | 
| 
       86 
     | 
    
         
            -
            			 
     | 
| 
       87 
     | 
    
         
            -
            			 
     | 
| 
       88 
     | 
    
         
            -
            		end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
            		def join_ table, model, query, pretable = nil
         
     | 
| 
       91 
     | 
    
         
            -
            			pretable ||= table[0...-1]
         
     | 
| 
      
 80 
     | 
    
         
            +
            		def join table, model
         
     | 
| 
      
 81 
     | 
    
         
            +
            			return self  if @_joined.include? table # Already joined
         
     | 
| 
      
 82 
     | 
    
         
            +
            			pretable = table[0...-1]
         
     | 
| 
       92 
83 
     | 
    
         
             
            			@table_model[ table] = model
         
     | 
| 
       93 
84 
     | 
    
         
             
            			premodel = @table_model[ pretable]
         
     | 
| 
       94 
85 
     | 
    
         
             
            			t = @table_alias[ table]
         
     | 
| 
       95 
86 
     | 
    
         
             
            			pt = quote_table_name @table_alias[ table[ 0...-1]]
         
     | 
| 
       96 
87 
     | 
    
         
             
            			refl = premodel.reflections[table.last]
         
     | 
| 
       97 
     | 
    
         
            -
            			case refl
         
     | 
| 
       98 
     | 
    
         
            -
            			when  
     | 
| 
       99 
     | 
    
         
            -
            				 
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
            				 
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
            				 
     | 
| 
       104 
     | 
    
         
            -
            				 
     | 
| 
       105 
     | 
    
         
            -
            				 
     | 
| 
       106 
     | 
    
         
            -
            			 
     | 
| 
       107 
     | 
    
         
            -
            				case refl.macro
         
     | 
| 
       108 
     | 
    
         
            -
            				when :has_many
         
     | 
| 
       109 
     | 
    
         
            -
            					@_joins += build_join query, pretable, t, premodel.primary_key, refl.primary_key_name
         
     | 
| 
       110 
     | 
    
         
            -
            				when :belongs_to
         
     | 
| 
       111 
     | 
    
         
            -
            					@_joins += build_join query, pretable, t, refl.primary_key_name, premodel.primary_key
         
     | 
| 
       112 
     | 
    
         
            -
            				when :has_and_belongs_to_many
         
     | 
| 
       113 
     | 
    
         
            -
            					jointable = [','] + table
         
     | 
| 
       114 
     | 
    
         
            -
            					@_joins += build_join refl.options[:join_table], pretable, @table_alias[jointable], premodel.primary_key, refl.primary_key_name
         
     | 
| 
       115 
     | 
    
         
            -
            					@_joins += build_join query, jointable, t, refl.association_foreign_key, refl.association_primary_key
         
     | 
| 
       116 
     | 
    
         
            -
            				else raise BuilderError, "Unkown reflection macro: #{refl.macro.inspect}"
         
     | 
| 
       117 
     | 
    
         
            -
            				end
         
     | 
| 
       118 
     | 
    
         
            -
            			else raise BuilderError, "Unkown reflection type: #{refl.class.name}"
         
     | 
| 
      
 88 
     | 
    
         
            +
            			case refl.macro
         
     | 
| 
      
 89 
     | 
    
         
            +
            			when :has_many
         
     | 
| 
      
 90 
     | 
    
         
            +
            				@_joins += build_join model.table_name, pretable, t, premodel.primary_key, refl.primary_key_name
         
     | 
| 
      
 91 
     | 
    
         
            +
            			when :belongs_to
         
     | 
| 
      
 92 
     | 
    
         
            +
            				@_joins += build_join model.table_name, pretable, t, refl.primary_key_name, premodel.primary_key
         
     | 
| 
      
 93 
     | 
    
         
            +
            			when :has_and_belongs_to_many
         
     | 
| 
      
 94 
     | 
    
         
            +
            				jointable = [','] + table
         
     | 
| 
      
 95 
     | 
    
         
            +
            				@_joins += build_join refl.options[:join_table], pretable, @table_alias[jointable], premodel.primary_key, refl.primary_key_name
         
     | 
| 
      
 96 
     | 
    
         
            +
            				@_joins += build_join model.table_name, jointable, t, refl.association_foreign_key, refl.association_primary_key
         
     | 
| 
      
 97 
     | 
    
         
            +
            			else raise BuilderError, "Unkown reflection macro: #{refl.macro.inspect}"
         
     | 
| 
       119 
98 
     | 
    
         
             
            			end
         
     | 
| 
       120 
     | 
    
         
            -
            			self
         
     | 
| 
       121 
     | 
    
         
            -
            		end
         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
            		def joins table, model
         
     | 
| 
       124 
     | 
    
         
            -
            			table = table.flatten.compact
         
     | 
| 
       125 
     | 
    
         
            -
            			return self  if @_joined.include? table # Already joined
         
     | 
| 
       126 
     | 
    
         
            -
            			join_ table, model, quote_table_name( model.table_name)
         
     | 
| 
       127 
99 
     | 
    
         
             
            			@_joined.push table
         
     | 
| 
      
 100 
     | 
    
         
            +
            			self
         
     | 
| 
       128 
101 
     | 
    
         
             
            		end
         
     | 
| 
       129 
102 
     | 
    
         | 
| 
       130 
103 
     | 
    
         
             
            		def includes table
         
     | 
| 
         @@ -138,25 +111,36 @@ class SmqlToAR 
     | 
|
| 
       138 
111 
     | 
    
         
             
            		end
         
     | 
| 
       139 
112 
     | 
    
         | 
| 
       140 
113 
     | 
    
         
             
            		def order table, col, o
         
     | 
| 
       141 
     | 
    
         
            -
            			 
     | 
| 
      
 114 
     | 
    
         
            +
            			tc = column table, col
         
     | 
| 
      
 115 
     | 
    
         
            +
            			@_select.push ct
         
     | 
| 
      
 116 
     | 
    
         
            +
            			@_order.push "#{ct} #{:DESC == o ? :DESC : :ASC}"
         
     | 
| 
      
 117 
     | 
    
         
            +
            			self
         
     | 
| 
      
 118 
     | 
    
         
            +
            		end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
            		class Dummy
         
     | 
| 
      
 121 
     | 
    
         
            +
            			def method_missing m, *a, &e
         
     | 
| 
      
 122 
     | 
    
         
            +
            				#p :dummy => m, :pars => a, :block => e
         
     | 
| 
      
 123 
     | 
    
         
            +
            				self
         
     | 
| 
      
 124 
     | 
    
         
            +
            			end
         
     | 
| 
       142 
125 
     | 
    
         
             
            		end
         
     | 
| 
       143 
126 
     | 
    
         | 
| 
       144 
127 
     | 
    
         
             
            		def build_ar
         
     | 
| 
       145 
     | 
    
         
            -
            			where_str = @_where. 
     | 
| 
      
 128 
     | 
    
         
            +
            			where_str = @_where.collect do |w|
         
     | 
| 
      
 129 
     | 
    
         
            +
            				w = Array.wrap w
         
     | 
| 
      
 130 
     | 
    
         
            +
            				1 == w.length ? w.first : "( #{w.join( ' OR ')} )"
         
     | 
| 
      
 131 
     | 
    
         
            +
            			end.join ' AND '
         
     | 
| 
       146 
132 
     | 
    
         
             
            			incls = {}
         
     | 
| 
       147 
133 
     | 
    
         
             
            			@_includes.each do |inc|
         
     | 
| 
       148 
134 
     | 
    
         
             
            				b = incls
         
     | 
| 
       149 
135 
     | 
    
         
             
            				inc[1..-1].collect {|rel| b = b[rel] ||= {} }
         
     | 
| 
       150 
136 
     | 
    
         
             
            			end
         
     | 
| 
      
 137 
     | 
    
         
            +
            			@logger.debug incls: incls, joins: @_joins
         
     | 
| 
       151 
138 
     | 
    
         
             
            			@model = @model.
         
     | 
| 
       152 
139 
     | 
    
         
             
            				select( @_select.join( ', ')).
         
     | 
| 
       153 
140 
     | 
    
         
             
            				joins( @_joins).
         
     | 
| 
       154 
141 
     | 
    
         
             
            				where( where_str, @_wobs).
         
     | 
| 
       155 
142 
     | 
    
         
             
            				order( @_order.join( ', ')).
         
     | 
| 
       156 
143 
     | 
    
         
             
            				includes( incls)
         
     | 
| 
       157 
     | 
    
         
            -
            			@model = @model.limit @limit  if @limit
         
     | 
| 
       158 
     | 
    
         
            -
            			@model = @model.offset @offset  if @offset
         
     | 
| 
       159 
     | 
    
         
            -
            			@model
         
     | 
| 
       160 
144 
     | 
    
         
             
            		end
         
     | 
| 
       161 
145 
     | 
    
         | 
| 
       162 
146 
     | 
    
         
             
            		def fix_calculate
         
     | 
| 
         @@ -175,72 +159,4 @@ class SmqlToAR 
     | 
|
| 
       175 
159 
     | 
    
         
             
            			@model
         
     | 
| 
       176 
160 
     | 
    
         
             
            		end
         
     | 
| 
       177 
161 
     | 
    
         
             
            	end
         
     | 
| 
       178 
     | 
    
         
            -
             
     | 
| 
       179 
     | 
    
         
            -
            	class SubBuilder < Array
         
     | 
| 
       180 
     | 
    
         
            -
            		attr_reader :parent, :_where
         
     | 
| 
       181 
     | 
    
         
            -
            		delegate :wobs, :joins, :includes, :sub_joins, :vid, :quote_column_name, :quoter, :quote_table_name, :column, :to => :parent
         
     | 
| 
       182 
     | 
    
         
            -
             
     | 
| 
       183 
     | 
    
         
            -
            		def initialize parent, tmp = false
         
     | 
| 
       184 
     | 
    
         
            -
            			@parent = parent
         
     | 
| 
       185 
     | 
    
         
            -
            			@parent.where self  unless @parend.nil? && tmp
         
     | 
| 
       186 
     | 
    
         
            -
            		end
         
     | 
| 
       187 
     | 
    
         
            -
             
     | 
| 
       188 
     | 
    
         
            -
            		def new parent, tmp = false
         
     | 
| 
       189 
     | 
    
         
            -
            			super parent, tmp
         
     | 
| 
       190 
     | 
    
         
            -
            			#return parent  if self.class == parent.class
         
     | 
| 
       191 
     | 
    
         
            -
            			#super parent
         
     | 
| 
       192 
     | 
    
         
            -
            		end
         
     | 
| 
       193 
     | 
    
         
            -
             
     | 
| 
       194 
     | 
    
         
            -
            		alias where push
         
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
            		def type_correction!
         
     | 
| 
       197 
     | 
    
         
            -
            			collect! do |sub|
         
     | 
| 
       198 
     | 
    
         
            -
            				if sub.kind_of? Array
         
     | 
| 
       199 
     | 
    
         
            -
            					sub = default[ *sub]  unless sub.respond_to?( :type_correction!)
         
     | 
| 
       200 
     | 
    
         
            -
            					sub.type_correction!
         
     | 
| 
       201 
     | 
    
         
            -
            				end
         
     | 
| 
       202 
     | 
    
         
            -
            				sub
         
     | 
| 
       203 
     | 
    
         
            -
            			end
         
     | 
| 
       204 
     | 
    
         
            -
            			self
         
     | 
| 
       205 
     | 
    
         
            -
            		end
         
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
       207 
     | 
    
         
            -
            		def optimize!
         
     | 
| 
       208 
     | 
    
         
            -
            			ext = []
         
     | 
| 
       209 
     | 
    
         
            -
            			collect! do |sub|
         
     | 
| 
       210 
     | 
    
         
            -
            				sub = sub.optimize!  if sub.kind_of? Array
         
     | 
| 
       211 
     | 
    
         
            -
            				if self.class == sub.class
         
     | 
| 
       212 
     | 
    
         
            -
            					ext.push *sub
         
     | 
| 
       213 
     | 
    
         
            -
            					nil
         
     | 
| 
       214 
     | 
    
         
            -
            				elsif sub.blank?
         
     | 
| 
       215 
     | 
    
         
            -
            					nil
         
     | 
| 
       216 
     | 
    
         
            -
            				else
         
     | 
| 
       217 
     | 
    
         
            -
            					sub
         
     | 
| 
       218 
     | 
    
         
            -
            				end
         
     | 
| 
       219 
     | 
    
         
            -
            			end.compact!
         
     | 
| 
       220 
     | 
    
         
            -
            			push *ext
         
     | 
| 
       221 
     | 
    
         
            -
            			self
         
     | 
| 
       222 
     | 
    
         
            -
            		end
         
     | 
| 
       223 
     | 
    
         
            -
             
     | 
| 
       224 
     | 
    
         
            -
            		def inspect
         
     | 
| 
       225 
     | 
    
         
            -
            			"#{self.class.name.sub( /.*::/, '')}[ #{collect(&:inspect).join ', '}]"
         
     | 
| 
       226 
     | 
    
         
            -
            		end
         
     | 
| 
       227 
     | 
    
         
            -
            		def default()  SmqlToAR::And  end
         
     | 
| 
       228 
     | 
    
         
            -
            		def default_new( parent)  default.new self, parent, false  end
         
     | 
| 
       229 
     | 
    
         
            -
            		def collect_build_where
         
     | 
| 
       230 
     | 
    
         
            -
            			collect {|x| x.respond_to?( :build_where) ? x.build_where : x.to_s }
         
     | 
| 
       231 
     | 
    
         
            -
            		end
         
     | 
| 
       232 
     | 
    
         
            -
            	end
         
     | 
| 
       233 
     | 
    
         
            -
             
     | 
| 
       234 
     | 
    
         
            -
            	class And < SubBuilder
         
     | 
| 
       235 
     | 
    
         
            -
            		def default; SmqlToAR::Or; end
         
     | 
| 
       236 
     | 
    
         
            -
            		def build_where
         
     | 
| 
       237 
     | 
    
         
            -
            			collect_build_where.join ' AND '
         
     | 
| 
       238 
     | 
    
         
            -
            		end
         
     | 
| 
       239 
     | 
    
         
            -
            	end
         
     | 
| 
       240 
     | 
    
         
            -
             
     | 
| 
       241 
     | 
    
         
            -
            	class Or < SubBuilder
         
     | 
| 
       242 
     | 
    
         
            -
            		def build_where
         
     | 
| 
       243 
     | 
    
         
            -
            			collect_build_where.join ' OR '
         
     | 
| 
       244 
     | 
    
         
            -
            		end
         
     | 
| 
       245 
     | 
    
         
            -
            	end
         
     | 
| 
       246 
162 
     | 
    
         
             
            end
         
     | 
    
        data/lib/smql_to_ar.rb
    CHANGED
    
    | 
         @@ -15,18 +15,6 @@ 
     | 
|
| 
       15 
15 
     | 
    
         
             
            # along with this program.  If not, see <http://www.gnu.org/licenses/>.
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
            class SmqlToAR
         
     | 
| 
       18 
     | 
    
         
            -
            	module Assertion
         
     | 
| 
       19 
     | 
    
         
            -
            		def raise_unless cond, exception = nil, *args
         
     | 
| 
       20 
     | 
    
         
            -
            			cond, exception, *args = yield. cond, exception, *args  if block_given?
         
     | 
| 
       21 
     | 
    
         
            -
            			raise exception || Exception, *args  unless cond
         
     | 
| 
       22 
     | 
    
         
            -
            		end
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
            		def raise_if cond, exception = nil, *args
         
     | 
| 
       25 
     | 
    
         
            -
            			cond, exception, *args = yield. cond, exception, *args  if block_given?
         
     | 
| 
       26 
     | 
    
         
            -
            			raise exception || Exception, *args  if cond
         
     | 
| 
       27 
     | 
    
         
            -
            		end
         
     | 
| 
       28 
     | 
    
         
            -
            	end
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
18 
     | 
    
         
             
            	include ActiveSupport::Benchmarkable
         
     | 
| 
       31 
19 
     | 
    
         
             
            	############################################################################r
         
     | 
| 
       32 
20 
     | 
    
         
             
            	# Exceptions
         
     | 
| 
         @@ -89,27 +77,19 @@ class SmqlToAR 
     | 
|
| 
       89 
77 
     | 
    
         
             
            		end
         
     | 
| 
       90 
78 
     | 
    
         
             
             	end
         
     | 
| 
       91 
79 
     | 
    
         | 
| 
       92 
     | 
    
         
            -
            	class  
     | 
| 
      
 80 
     | 
    
         
            +
            	class OnlyOrderOnBaseError < SMQLError
         
     | 
| 
       93 
81 
     | 
    
         
             
            		def initialize path
         
     | 
| 
       94 
82 
     | 
    
         
             
            			super :path => path
         
     | 
| 
       95 
83 
     | 
    
         
             
            		end
         
     | 
| 
       96 
84 
     | 
    
         
             
            	end
         
     | 
| 
       97 
85 
     | 
    
         | 
| 
       98 
     | 
    
         
            -
            	class ConColumnError < SMQLError
         
     | 
| 
       99 
     | 
    
         
            -
            		def initialize expected, got
         
     | 
| 
       100 
     | 
    
         
            -
            			super :expected => expected, :got => got
         
     | 
| 
       101 
     | 
    
         
            -
            		end
         
     | 
| 
       102 
     | 
    
         
            -
            	end
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
86 
     | 
    
         
             
            	class BuilderError < Exception; end
         
     | 
| 
       105 
87 
     | 
    
         | 
| 
       106 
88 
     | 
    
         
             
            	#############################################################################
         
     | 
| 
       107 
89 
     | 
    
         | 
| 
       108 
90 
     | 
    
         
             
            	# Model der Relation `rel` von `model`
         
     | 
| 
       109 
91 
     | 
    
         
             
            	def self.model_of model, rel
         
     | 
| 
       110 
     | 
    
         
            -
            		 
     | 
| 
       111 
     | 
    
         
            -
            		r = model.reflections[ rel].andand.klass
         
     | 
| 
       112 
     | 
    
         
            -
            		r.nil? && :self == rel ? model : r
         
     | 
| 
      
 92 
     | 
    
         
            +
            		model.reflections[ rel.to_sym].andand.klass
         
     | 
| 
       113 
93 
     | 
    
         
             
            	end
         
     | 
| 
       114 
94 
     | 
    
         | 
| 
       115 
95 
     | 
    
         
             
            	# Eine Spalte in einer Tabelle, relativ zu `Column#model`.
         
     | 
| 
         @@ -123,7 +103,7 @@ class SmqlToAR 
     | 
|
| 
       123 
103 
     | 
    
         
             
            		def initialize model, *col
         
     | 
| 
       124 
104 
     | 
    
         
             
            			@model = model
         
     | 
| 
       125 
105 
     | 
    
         
             
            			@last_model = nil
         
     | 
| 
       126 
     | 
    
         
            -
            			*@path, @col =  
     | 
| 
      
 106 
     | 
    
         
            +
            			*@path, @col = Array.wrap( col).collect {|s| s.to_s.split /[.\/]/ }.flatten.collect &:to_sym
         
     | 
| 
       127 
107 
     | 
    
         
             
            		end
         
     | 
| 
       128 
108 
     | 
    
         | 
| 
       129 
109 
     | 
    
         
             
            		def last_model
         
     | 
| 
         @@ -133,12 +113,9 @@ class SmqlToAR 
     | 
|
| 
       133 
113 
     | 
    
         
             
            		def each
         
     | 
| 
       134 
114 
     | 
    
         
             
            			model = @model
         
     | 
| 
       135 
115 
     | 
    
         
             
            			@path.each do |rel|
         
     | 
| 
       136 
     | 
    
         
            -
            				 
     | 
| 
       137 
     | 
    
         
            -
            				unless  
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
            					return false  unless model
         
     | 
| 
       140 
     | 
    
         
            -
            					yield rel, model
         
     | 
| 
       141 
     | 
    
         
            -
            				end
         
     | 
| 
      
 116 
     | 
    
         
            +
            				model = SmqlToAR.model_of model, rel
         
     | 
| 
      
 117 
     | 
    
         
            +
            				return false  unless model
         
     | 
| 
      
 118 
     | 
    
         
            +
            				yield rel, model
         
     | 
| 
       142 
119 
     | 
    
         
             
            			end
         
     | 
| 
       143 
120 
     | 
    
         
             
            			model
         
     | 
| 
       144 
121 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -163,23 +140,19 @@ class SmqlToAR 
     | 
|
| 
       163 
140 
     | 
    
         
             
            		def joins builder = nil, table = nil, &exe
         
     | 
| 
       164 
141 
     | 
    
         
             
            			pp = []
         
     | 
| 
       165 
142 
     | 
    
         
             
            			table = Array.wrap table
         
     | 
| 
       166 
     | 
    
         
            -
            			exe ||= builder ? lambda {|j, m| builder. 
     | 
| 
      
 143 
     | 
    
         
            +
            			exe ||= builder ? lambda {|j, m| builder.join table+j, m} : Array.method( :[])
         
     | 
| 
       167 
144 
     | 
    
         
             
            			collect do |rel, model|
         
     | 
| 
       168 
145 
     | 
    
         
             
            				pp.push rel
         
     | 
| 
       169 
146 
     | 
    
         
             
            				exe.call pp, model
         
     | 
| 
       170 
147 
     | 
    
         
             
            			end
         
     | 
| 
       171 
148 
     | 
    
         
             
            	 	end
         
     | 
| 
       172 
     | 
    
         
            -
            		def  
     | 
| 
       173 
     | 
    
         
            -
            		def length() @path.length+(self.self? ? 0 : 1)  end
         
     | 
| 
       174 
     | 
    
         
            -
            		def size()   @path.size+(self.self? ? 0 : 1)  end
         
     | 
| 
       175 
     | 
    
         
            -
            		def to_a()   @path+(self.self? ? [] : [@col])  end
         
     | 
| 
      
 149 
     | 
    
         
            +
            		def to_a()   @path+[@col]  end
         
     | 
| 
       176 
150 
     | 
    
         
             
            		def to_s()   to_a.join '.'  end
         
     | 
| 
       177 
151 
     | 
    
         
             
            		def to_sym() to_s.to_sym  end
         
     | 
| 
       178 
152 
     | 
    
         
             
            		def to_json()  to_s  end
         
     | 
| 
       179 
153 
     | 
    
         
             
            		def inspect()  "#<Column: #{model} #{to_s}>"  end
         
     | 
| 
       180 
     | 
    
         
            -
            		def relation()   
     | 
| 
      
 154 
     | 
    
         
            +
            		def relation()  SmqlToAR.model_of last_model, @col  end
         
     | 
| 
       181 
155 
     | 
    
         
             
            		def allowed?()  ! self.protected?  end
         
     | 
| 
       182 
     | 
    
         
            -
            		def child?()  @path.empty? and !!relation  end
         
     | 
| 
       183 
156 
     | 
    
         
             
            	end
         
     | 
| 
       184 
157 
     | 
    
         | 
| 
       185 
158 
     | 
    
         
             
            	attr_reader :model, :query, :conditions, :builder, :order
         
     | 
| 
         @@ -206,23 +179,6 @@ class SmqlToAR 
     | 
|
| 
       206 
179 
     | 
    
         
             
            		#p model: @model, query: @query
         
     | 
| 
       207 
180 
     | 
    
         
             
            	end
         
     | 
| 
       208 
181 
     | 
    
         | 
| 
       209 
     | 
    
         
            -
            	def self.models models
         
     | 
| 
       210 
     | 
    
         
            -
            		models = Array.wrap models
         
     | 
| 
       211 
     | 
    
         
            -
            		r = Hash.new {|h,k| h[k] = {} }
         
     | 
| 
       212 
     | 
    
         
            -
            		while model = models.tap( &:uniq!).pop
         
     | 
| 
       213 
     | 
    
         
            -
            			refls = model.respond_to?( :reflections) && model.reflections
         
     | 
| 
       214 
     | 
    
         
            -
            			refls && refls.each do |name, refl|
         
     | 
| 
       215 
     | 
    
         
            -
            				r[model.name][name] = case refl
         
     | 
| 
       216 
     | 
    
         
            -
            					when ActiveRecord::Reflection::ThroughReflection then {:macro => refl.macro, :model => refl.klass.name, :through => refl.through_reflection.name}
         
     | 
| 
       217 
     | 
    
         
            -
            					when ActiveRecord::Reflection::AssociationReflection then {:macro => refl.macro, :model => refl.klass.name}
         
     | 
| 
       218 
     | 
    
         
            -
            					else raise "Ups: #{refl.class}"
         
     | 
| 
       219 
     | 
    
         
            -
            					end
         
     | 
| 
       220 
     | 
    
         
            -
            				models.push refl.klass  unless r.keys.include? refl.klass.name
         
     | 
| 
       221 
     | 
    
         
            -
            			end
         
     | 
| 
       222 
     | 
    
         
            -
            		end
         
     | 
| 
       223 
     | 
    
         
            -
            		r
         
     | 
| 
       224 
     | 
    
         
            -
            	end
         
     | 
| 
       225 
     | 
    
         
            -
             
     | 
| 
       226 
182 
     | 
    
         
             
            	def parse
         
     | 
| 
       227 
183 
     | 
    
         
             
            		benchmark 'SMQL parse' do
         
     | 
| 
       228 
184 
     | 
    
         
             
            			@conditions = ConditionTypes.try_parse @model, @query
         
     | 
| 
         @@ -231,11 +187,11 @@ class SmqlToAR 
     | 
|
| 
       231 
187 
     | 
    
         
             
            		self
         
     | 
| 
       232 
188 
     | 
    
         
             
            	end
         
     | 
| 
       233 
189 
     | 
    
         | 
| 
       234 
     | 
    
         
            -
            	def build 
     | 
| 
      
 190 
     | 
    
         
            +
            	def build
         
     | 
| 
       235 
191 
     | 
    
         
             
            		benchmark 'SMQL build query' do
         
     | 
| 
       236 
     | 
    
         
            -
            			@builder = QueryBuilder.new @model 
     | 
| 
      
 192 
     | 
    
         
            +
            			@builder = QueryBuilder.new @model
         
     | 
| 
       237 
193 
     | 
    
         
             
            			table = @builder.base_table
         
     | 
| 
       238 
     | 
    
         
            -
            			@conditions.each  
     | 
| 
      
 194 
     | 
    
         
            +
            			@conditions.each {|condition| condition.build builder, table }
         
     | 
| 
       239 
195 
     | 
    
         
             
            		end
         
     | 
| 
       240 
196 
     | 
    
         
             
            		#p builder: @builder
         
     | 
| 
       241 
197 
     | 
    
         
             
            		self
         
     | 
| 
         @@ -258,12 +214,4 @@ class SmqlToAR 
     | 
|
| 
       258 
214 
     | 
    
         
             
            	def self.to_ar *params
         
     | 
| 
       259 
215 
     | 
    
         
             
            		new( *params).to_ar
         
     | 
| 
       260 
216 
     | 
    
         
             
            	end
         
     | 
| 
       261 
     | 
    
         
            -
             
     | 
| 
       262 
     | 
    
         
            -
            	def self.reload_library
         
     | 
| 
       263 
     | 
    
         
            -
            		lib_dir = File.dirname __FILE__
         
     | 
| 
       264 
     | 
    
         
            -
            		fj = lambda {|*a| File.join lib_dir, *a }
         
     | 
| 
       265 
     | 
    
         
            -
            		load fj.call( 'smql_to_ar.rb')
         
     | 
| 
       266 
     | 
    
         
            -
            		load fj.call( 'smql_to_ar', 'condition_types.rb')
         
     | 
| 
       267 
     | 
    
         
            -
            		load fj.call( 'smql_to_ar', 'query_builder.rb')
         
     | 
| 
       268 
     | 
    
         
            -
            	end
         
     | 
| 
       269 
217 
     | 
    
         
             
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version 
     | 
|
| 
       6 
6 
     | 
    
         
             
              - 0
         
     | 
| 
       7 
7 
     | 
    
         
             
              - 0
         
     | 
| 
       8 
8 
     | 
    
         
             
              - 4
         
     | 
| 
       9 
     | 
    
         
            -
              -  
     | 
| 
       10 
     | 
    
         
            -
              version: 0.0.4. 
     | 
| 
      
 9 
     | 
    
         
            +
              - 2
         
     | 
| 
      
 10 
     | 
    
         
            +
              version: 0.0.4.2
         
     | 
| 
       11 
11 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       12 
12 
     | 
    
         
             
            authors: 
         
     | 
| 
       13 
13 
     | 
    
         
             
            - Denis Knauf
         
     | 
| 
         @@ -15,7 +15,7 @@ autorequire: 
     | 
|
| 
       15 
15 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       16 
16 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
            date: 2011-10- 
     | 
| 
      
 18 
     | 
    
         
            +
            date: 2011-10-27 00:00:00 +02:00
         
     | 
| 
       19 
19 
     | 
    
         
             
            default_executable: 
         
     | 
| 
       20 
20 
     | 
    
         
             
            dependencies: 
         
     | 
| 
       21 
21 
     | 
    
         
             
            - !ruby/object:Gem::Dependency 
         
     |