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 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