"self" and or

=============

This lines mean the same:

	User.smql :self => {:id => 1}
	User.smql :id => 1
	User.smql 'self.id' => 1
	User.smql 'self.self.self.self.id' => 1

self is like a reflection to itself.

Very userful if you need the new disjunction:

	User.smql :self => [{:surname => 'Mueller', :givenname => 'Michael'}, {:givenname => 'Horst', :surname => 'Schlemmer'}], :firm => {:name => 'Hotel an der Elbe'}

SmqlToAR::Column
----------------

Rejects every `self`,  so it is really like no self,
but you use `'self'` as like as a simple reflection.
You can ask,  if it is self via Column#self?

SmqlToAR::QueryBuilder
======================

joins:  The old `#join`. Renames because SmqlToAR::And and SmqlToAR::Or which has Array#join,
        so we cannot delegate `#join` to the QueryBuilder.

`#where`
--------

Now only one argument!  Needed for SmqlToAR::And and SmqlToAR::Or.

`#build` will generates LEFT OUTER JOINS now.  Needed for disjunctions.
The most queries will work like before.
Problems:

	User.smql :articles => {}

Before it will return all users with articles,  now it will return also users without articles.
If you want to have only all users with articles,  you ask:

	User.smql :articles => {:id => true}

Will fail if id IS NULL,  but this should not happen. ;)

`SmqlToAR::And` and `SmqlToAR::Or`
==================================

`SmqlToAR::QueryBuilder`-proxies.  QueryBuilder let them build where-clauses.
And will will produce a conjunction and  Or a disjunction of course.
They delegates all QueryBuilder-methods to QueryBuilder.
Only `#where` will stored local and `#build` will do it partial.

They have the same superclass: `SmqlToAR::SubBuilder`.

The small changes
=================

* `SmqlToAR.reload_library`:  Reloads SmqlToAR-lib.  Useful while development.
* `SmqlToAR::ConditionTypes#conditions`:  Return all Conditions.  `#try_parse` uses it.
* Some classes have a new `#inspect`.
* `SmqlToAR::ConditionTypes#Exists` / `NotExists`:
  `{:id => true}` / `{:id => false}`:
  This object has setted an id or not?  `#id` must exists as column of course!
	Uses `IS NOT NULL` and `IS NULL`.
This commit is contained in:
Denis Knauf 2011-10-05 13:25:56 +02:00
parent 93fd3eeda4
commit 2fdc45d1d5
3 changed files with 184 additions and 73 deletions

View file

@ -107,7 +107,9 @@ class SmqlToAR
# Model der Relation `rel` von `model`
def self.model_of model, rel
model.reflections[ rel.to_sym].andand.klass
rel = rel.to_sym
r = model.reflections[ rel].andand.klass
r.nil? && :self == rel ? model : r
end
# Eine Spalte in einer Tabelle, relativ zu `Column#model`.
@ -121,7 +123,7 @@ class SmqlToAR
def initialize model, *col
@model = model
@last_model = nil
*@path, @col = Array.wrap( col).collect( &it.to_s.split( /[.\/]/)).flatten.collect( &:to_sym)
*@path, @col = *Array.wrap( col).collect( &it.to_s.split( /[.\/]/)).flatten.collect( &:to_sym).reject( &it==:self)
end
def last_model
@ -131,9 +133,12 @@ class SmqlToAR
def each
model = @model
@path.each do |rel|
model = SmqlToAR.model_of model, rel
return false unless model
yield rel, model
rel = rel.to_sym
unless :self == rel
model = SmqlToAR.model_of model, rel
return false unless model
yield rel, model
end
end
model
end
@ -158,20 +163,21 @@ class SmqlToAR
def joins builder = nil, table = nil, &exe
pp = []
table = Array.wrap table
exe ||= builder ? lambda {|j, m| builder.join table+j, m} : Array.method( :[])
exe ||= builder ? lambda {|j, m| builder.joins table+j, m} : Array.method( :[])
collect do |rel, model|
pp.push rel
exe.call pp, model
end
end
def length() @path.length+1 end
def size() @path.size+1 end
def to_a() @path+[@col] end
def self?() !@col end
def length() @path.length+(self.self? ? 0 : 1) end
def size() @path.size+(self.self? ? 0 : 1) end
def to_a() @path+(self.self? ? [] : [@col]) end
def to_s() to_a.join '.' end
def to_sym() to_s.to_sym end
def to_json() to_s end
def inspect() "#<Column: #{model} #{to_s}>" end
def relation() SmqlToAR.model_of last_model, @col end
def relation() self.self? ? model : SmqlToAR.model_of( last_model, @col) end
def allowed?() ! self.protected? end
def child?() @path.empty? and !!relation end
end
@ -225,9 +231,9 @@ class SmqlToAR
self
end
def build prefix = nil, base_table = nil
def build prefix = nil
benchmark 'SMQL build query' do
@builder = QueryBuilder.new @model, prefix, base_table
@builder = QueryBuilder.new @model, prefix
table = @builder.base_table
@conditions.each &it.build( builder, table)
end
@ -252,4 +258,12 @@ class SmqlToAR
def self.to_ar *params
new( *params).to_ar
end
def self.reload_library
lib_dir = File.dirname __FILE__
fj = lambda {|*a| File.join lib_dir, *a }
load fj.call( 'smql_to_ar.rb')
load fj.call( 'smql_to_ar', 'condition_types.rb')
load fj.call( 'smql_to_ar', 'query_builder.rb')
end
end