smql 0.0.4.1 → 0.0.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4.1
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
- conditions.each do |c|
59
- raise_unless colop =~ /^(?:\d*:)?(.*?)(\W*)$/, UnexpectedColOpError.new( model, colop, val)
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
- raise_unless r, UnexpectedError.new( model, colop, val)
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
- class <<self
99
- # Versuche das Objekt zu erkennen. Operator und Expected muessen passen.
100
- # Passt das Object, die Klasse instanzieren.
101
- def try_parse model, cols, op, val
102
- #p :self => name, :try_parse => op, :cols => cols, :with => self::Operator, :value => val, :expected => self::Expected, :model => model.name
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
- raise_unless col.exist_in?, NonExistingColumnError.new( %w[Column], col)
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
- raise_if col.protected?, ProtectedColumnError.new( col)
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.joins, builder.select, builder.where und builder.wobs von interesse sind.
146
- # mehrere Schluessel bedeuten, dass die Values _alle_ zutreffen muessen, wobei die Schluessel geODERt werden.
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
- b2.where SmqlToAR::Or[ *@cols.collect {|col|
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, '!=', "%s <> %s", [Array, String, Numeric]
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, lambda {|x| x.kind_of?( Array) and x.all?( &it.kind_of?( 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.relation
235
- cols[col] = [col_model] + @value.collect {|val| ConditionTypes.try_parse( col_model, val) }
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
- raise_unless col.relation, NonExistingRelationError.new( %w[Relation], col)
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
- col.joins.each {|j, m| builder.joins table+j, m }
249
- builder.joins t, model
250
- b2 = 1 == sub.length ? builder : Or.new( builder)
251
- sub.each {|i| i.collect( &it.build( And.new( b2), t)); p 'or' => b2 }
252
- end
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
- raise_unless col.exist_in? || SmqlToAR.model_of( col.last_model, col.col), NonExistingSelectableError.new( col)
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
- class <<self
338
- def try_parse model, func, args
339
- self.new model, func, args if self::Name === func and self::Expected.any?( &it === args)
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
- raise_unless col.exist_in?, NonExistingColumnError.new( [:Column], col)
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
- raise_unless 1 == t.length, RootOnlyFunctionError.new( t)
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() ":smql_c#{@vid}" end
26
- def to_sym() "smql_c#{@vid}".to_sym end
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, :prefix, :_vid
32
- attr_accessor :logger, :limit, :offset
31
+ attr_reader :table_alias, :model, :table_model, :base_table, :_where, :_select, :_wobs, :_joins
32
+ attr_accessor :logger
33
33
 
34
- def initialize model, prefix = nil
35
- @prefix = "smql"
34
+ def initialize model
36
35
  @logger = SmqlToAR.logger
37
36
  @table_alias = Hash.new do |h, k|
38
- j = Array.wrap( k).compact
39
- h[k] = h.key?(j) ? h[j] : "#{@prefix},#{j.join(',')}"
37
+ k = Array.wrap k
38
+ h[k] = "smql,#{k.join(',')}"
40
39
  end
41
- @_vid, @_where, @_wobs, @model, @quoter = 0, SmqlToAR::And[], {}, model, model.connection
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}.*"], "", [@base_table], [], []
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( ['a = a', 'b = c']).where( ['c = d', 'e = e']).where( 'x = y').where( ['( m = n AND o = p )', 'f = g'])
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
- " LEFT JOIN #{orig} AS #{quote_table_name table} ON #{column pretable, prekey} = #{column table, key} "
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 sub_joins table, col, model, query
86
- prefix, base_table = "#{@prefix}_sub", col.relation.table_name
87
- join_ table, model, "(#{query.build( prefix).ar.to_sql})"
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 ActiveRecord::Reflection::ThroughReflection
99
- through = refl.through_reflection
100
- throughtable = table[0...-1]+[through.name.to_sym]
101
- srctable = throughtable+[refl.source_reflection.name]
102
- @table_model[ srctable] = model
103
- @table_alias[ table] = @table_alias[ srctable]
104
- join_ throughtable, through.klass, quote_table_name( through.table_name)
105
- join_ srctable, refl.klass, query, throughtable
106
- when ActiveRecord::Reflection::AssociationReflection
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
- @_order.push "#{column table, col} #{:DESC == o ? :DESC : :ASC}"
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.type_correction!.optimize!.build_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 RootOnlyFunctionError < SMQLError
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
- rel = rel.to_sym
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 = *Array.wrap( col).collect( &it.to_s.split( /[.\/]/)).flatten.collect( &:to_sym).reject( &it==:self)
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
- rel = rel.to_sym
137
- unless :self == rel
138
- model = SmqlToAR.model_of model, rel
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.joins table+j, m} : Array.method( :[])
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 self?() !@col end
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() self.self? ? model : SmqlToAR.model_of( last_model, @col) end
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 prefix = nil
190
+ def build
235
191
  benchmark 'SMQL build query' do
236
- @builder = QueryBuilder.new @model, prefix
192
+ @builder = QueryBuilder.new @model
237
193
  table = @builder.base_table
238
- @conditions.each &it.build( builder, table)
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
- - 1
10
- version: 0.0.4.1
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-06 00:00:00 +02:00
18
+ date: 2011-10-27 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency