querybuilder 1.1.4 → 1.2.1
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/History.txt +12 -0
 - data/lib/query_builder/info.rb +2 -2
 - data/lib/query_builder/processor.rb +11 -7
 - data/lib/query_builder/query.rb +49 -35
 - data/querybuilder.gemspec +2 -2
 - data/test/querybuilder/basic.yml +6 -6
 - data/test/querybuilder/custom.yml +2 -2
 - data/test/querybuilder/filters.yml +4 -4
 - data/test/querybuilder/having.yml +1 -1
 - data/test/querybuilder/joins.yml +7 -7
 - data/test/querybuilder/mixed.yml +3 -3
 - data/test/querybuilder_test.rb +1 -1
 - metadata +4 -4
 
    
        data/History.txt
    CHANGED
    
    | 
         @@ -1,3 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            == 1.2.1 2013-03-11
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            * Major enhancement
         
     | 
| 
      
 4 
     | 
    
         
            +
              * "add_table" takes a block to configure join clause.
         
     | 
| 
      
 5 
     | 
    
         
            +
              * Fixed count queries with group and having clauses.
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            == 1.2.0 2012-10-10
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            * Major enhancement
         
     | 
| 
      
 10 
     | 
    
         
            +
              * All relations now use INNER JOIN with ON clause instead of using the WHERE filter. Custom processors *MUST*
         
     | 
| 
      
 11 
     | 
    
         
            +
                be changed to use the new add_table with :inner join type instead of using where filters.
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
       1 
13 
     | 
    
         
             
            == 1.1.4 2012-10-07
         
     | 
| 
       2 
14 
     | 
    
         | 
| 
       3 
15 
     | 
    
         
             
            * Major enhancement
         
     | 
    
        data/lib/query_builder/info.rb
    CHANGED
    
    | 
         @@ -1,3 +1,3 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module QueryBuilder
         
     | 
| 
       2 
     | 
    
         
            -
              VERSION = '1.1 
     | 
| 
       3 
     | 
    
         
            -
            end
         
     | 
| 
      
 2 
     | 
    
         
            +
              VERSION = '1.2.1'
         
     | 
| 
      
 3 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -792,13 +792,15 @@ module QueryBuilder 
     | 
|
| 
       792 
792 
     | 
    
         | 
| 
       793 
793 
     | 
    
         
             
                  # Add a new table and apply scoping when needed
         
     | 
| 
       794 
794 
     | 
    
         
             
                  def add_table(use_name, table_name = nil, type = nil, &block)
         
     | 
| 
      
 795 
     | 
    
         
            +
                    if use_name == main_table && first?
         
     | 
| 
      
 796 
     | 
    
         
            +
                      # we are now using final table
         
     | 
| 
      
 797 
     | 
    
         
            +
                      context[:table_alias] = use_name
         
     | 
| 
      
 798 
     | 
    
         
            +
                      avoid_alias = true
         
     | 
| 
      
 799 
     | 
    
         
            +
                    else
         
     | 
| 
      
 800 
     | 
    
         
            +
                      avoid_alias = false
         
     | 
| 
      
 801 
     | 
    
         
            +
                    end
         
     | 
| 
      
 802 
     | 
    
         
            +
             
     | 
| 
       795 
803 
     | 
    
         
             
                    if use_name == main_table
         
     | 
| 
       796 
     | 
    
         
            -
                      if first?
         
     | 
| 
       797 
     | 
    
         
            -
                        # we are now using final table
         
     | 
| 
       798 
     | 
    
         
            -
                        context[:table_alias] = use_name
         
     | 
| 
       799 
     | 
    
         
            -
                        avoid_alias = true
         
     | 
| 
       800 
     | 
    
         
            -
                      end
         
     | 
| 
       801 
     | 
    
         
            -
                      
         
     | 
| 
       802 
804 
     | 
    
         
             
                      if context[:scope_type] == :join
         
     | 
| 
       803 
805 
     | 
    
         
             
                        context[:scope_type] = nil
         
     | 
| 
       804 
806 
     | 
    
         
             
                        # pre scope
         
     | 
| 
         @@ -806,12 +808,14 @@ module QueryBuilder 
     | 
|
| 
       806 
808 
     | 
    
         
             
                          @query.add_table(main_table, main_table, avoid_alias)
         
     | 
| 
       807 
809 
     | 
    
         
             
                          apply_scope(context[:scope])
         
     | 
| 
       808 
810 
     | 
    
         
             
                        end
         
     | 
| 
      
 811 
     | 
    
         
            +
                        
         
     | 
| 
       809 
812 
     | 
    
         
             
                        @query.add_table(use_name, table_name, avoid_alias, type, &block)
         
     | 
| 
       810 
813 
     | 
    
         
             
                      elsif context[:scope_type] == :filter
         
     | 
| 
       811 
814 
     | 
    
         
             
                        context[:scope_type] = nil
         
     | 
| 
       812 
815 
     | 
    
         
             
                        # post scope
         
     | 
| 
       813 
     | 
    
         
            -
                        @query.add_table(use_name, table_name, avoid_alias)
         
     | 
| 
      
 816 
     | 
    
         
            +
                        tbl = @query.add_table(use_name, table_name, avoid_alias, &block)
         
     | 
| 
       814 
817 
     | 
    
         
             
                        apply_scope(context[:scope] || default_scope(context))
         
     | 
| 
      
 818 
     | 
    
         
            +
                        tbl
         
     | 
| 
       815 
819 
     | 
    
         
             
                      else
         
     | 
| 
       816 
820 
     | 
    
         
             
                        # scope already applied / skip
         
     | 
| 
       817 
821 
     | 
    
         
             
                        @query.add_table(use_name, table_name, avoid_alias, type, &block)
         
     | 
    
        data/lib/query_builder/query.rb
    CHANGED
    
    | 
         @@ -3,7 +3,7 @@ require 'active_record' 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module QueryBuilder
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Query
         
     | 
| 
       5 
5 
     | 
    
         
             
                SELECT_WITH_TYPE_REGEX = /^(.*):(.*)$/
         
     | 
| 
       6 
     | 
    
         
            -
                attr_accessor :processor_class, :distinct, :select, :tables, :table_alias, :where,
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :processor_class, :distinct, :select, :tables, :table_alias, :unique_alias, :where,
         
     | 
| 
       7 
7 
     | 
    
         
             
                              :limit, :offset, :page_size, :order, :group, :error, :attributes_alias,
         
     | 
| 
       8 
8 
     | 
    
         
             
                              :pagination_key, :main_class, :context, :key_value_tables, :having, :types
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
         @@ -16,8 +16,9 @@ module QueryBuilder 
     | 
|
| 
       16 
16 
     | 
    
         
             
                def initialize(processor_class)
         
     | 
| 
       17 
17 
     | 
    
         
             
                  @processor_class = processor_class
         
     | 
| 
       18 
18 
     | 
    
         
             
                  @tables = []
         
     | 
| 
       19 
     | 
    
         
            -
                  @table_alias 
     | 
| 
       20 
     | 
    
         
            -
                  @ 
     | 
| 
      
 19 
     | 
    
         
            +
                  @table_alias  = {}
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @unique_alias = {}
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @join_tables  = {}
         
     | 
| 
       21 
22 
     | 
    
         
             
                  @needed_join_tables = {}
         
     | 
| 
       22 
23 
     | 
    
         
             
                  @attributes_alias   = {}
         
     | 
| 
       23 
24 
     | 
    
         
             
                  # Custom select foo as bar:time or 'types:' field in custom query.
         
     | 
| 
         @@ -131,12 +132,12 @@ module QueryBuilder 
     | 
|
| 
       131 
132 
     | 
    
         
             
                  key_table = (key_tables[use_name] ||= {})
         
     | 
| 
       132 
133 
     | 
    
         
             
                  if alias_table = key_table[key]
         
     | 
| 
       133 
134 
     | 
    
         
             
                    # done, the index_table has been used for the given key in the current context
         
     | 
| 
      
 135 
     | 
    
         
            +
                    alias_table
         
     | 
| 
       134 
136 
     | 
    
         
             
                  else
         
     | 
| 
       135 
137 
     | 
    
         
             
                    # insert the new table
         
     | 
| 
       136 
     | 
    
         
            -
                     
     | 
| 
       137 
     | 
    
         
            -
                     
     | 
| 
      
 138 
     | 
    
         
            +
                    # Let caller configure the filter with &block.
         
     | 
| 
      
 139 
     | 
    
         
            +
                    key_table[key] = add_table(use_name + "_#{key}", index_table, false, :left, &block)
         
     | 
| 
       138 
140 
     | 
    
         
             
                  end
         
     | 
| 
       139 
     | 
    
         
            -
                  alias_table
         
     | 
| 
       140 
141 
     | 
    
         
             
                end
         
     | 
| 
       141 
142 
     | 
    
         | 
| 
       142 
143 
     | 
    
         
             
                def add_select(field, fname)
         
     | 
| 
         @@ -177,7 +178,7 @@ module QueryBuilder 
     | 
|
| 
       177 
178 
     | 
    
         
             
                # Duplicate query, avoiding sharing some arrays and hash
         
     | 
| 
       178 
179 
     | 
    
         
             
                def dup
         
     | 
| 
       179 
180 
     | 
    
         
             
                  other = super
         
     | 
| 
       180 
     | 
    
         
            -
                  %w{tables table_alias where tables key_value_tables}.each do |k|
         
     | 
| 
      
 181 
     | 
    
         
            +
                  %w{tables table_alias unique_alias where tables key_value_tables}.each do |k|
         
     | 
| 
       181 
182 
     | 
    
         
             
                    other.send("#{k}=", other.send(k).dup)
         
     | 
| 
       182 
183 
     | 
    
         
             
                  end
         
     | 
| 
       183 
184 
     | 
    
         
             
                  other
         
     | 
| 
         @@ -223,56 +224,63 @@ module QueryBuilder 
     | 
|
| 
       223 
224 
     | 
    
         
             
                def quote_column_name(name)
         
     | 
| 
       224 
225 
     | 
    
         
             
                  connection.quote_column_name(name)
         
     | 
| 
       225 
226 
     | 
    
         
             
                end
         
     | 
| 
       226 
     | 
    
         
            -
             
     | 
| 
       227 
     | 
    
         
            -
                def has_table?(use_name)
         
     | 
| 
       228 
     | 
    
         
            -
                  !@table_alias[use_name].nil?
         
     | 
| 
       229 
     | 
    
         
            -
                end
         
     | 
| 
       230 
     | 
    
         
            -
                
         
     | 
| 
       231 
     | 
    
         
            -
                
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
       232 
228 
     | 
    
         
             
                private
         
     | 
| 
       233 
     | 
    
         
            -
                  # Make sure each used table gets a unique name 
     | 
| 
       234 
     | 
    
         
            -
                  # But if 'avoid_alias' is true and it is the first call for this table, return the
         
     | 
| 
       235 
     | 
    
         
            -
                  # table without an alias.
         
     | 
| 
      
 229 
     | 
    
         
            +
                  # Make sure each used table gets a unique name
         
     | 
| 
       236 
230 
     | 
    
         
             
                  def get_alias(use_name, table_name = nil, avoid_alias = true)
         
     | 
| 
       237 
231 
     | 
    
         
             
                    table_name ||= use_name
         
     | 
| 
       238 
     | 
    
         
            -
             
     | 
| 
       239 
     | 
    
         
            -
                     
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                    base = use_name[0..1]
         
     | 
| 
      
 234 
     | 
    
         
            +
                    list  = (@unique_alias[base] ||= [])
         
     | 
| 
      
 235 
     | 
    
         
            +
                    list2 = @table_alias[use_name] ||= []
         
     | 
| 
      
 236 
     | 
    
         
            +
                    if avoid_alias && !@tables.include?(table_name)
         
     | 
| 
       240 
237 
     | 
    
         
             
                      alias_name = use_name
         
     | 
| 
       241 
238 
     | 
    
         
             
                    elsif @tables.include?(use_name)
         
     | 
| 
       242 
239 
     | 
    
         
             
                      # links, li1, li2, li3
         
     | 
| 
       243 
     | 
    
         
            -
                      alias_name = "#{ 
     | 
| 
      
 240 
     | 
    
         
            +
                      alias_name = "#{base}#{list.size}"
         
     | 
| 
       244 
241 
     | 
    
         
             
                    else
         
     | 
| 
       245 
242 
     | 
    
         
             
                      # ob1, obj2, objects
         
     | 
| 
       246 
     | 
    
         
            -
                      alias_name = "#{ 
     | 
| 
      
 243 
     | 
    
         
            +
                      alias_name = "#{base}#{list.size + 1}"
         
     | 
| 
       247 
244 
     | 
    
         
             
                    end
         
     | 
| 
       248 
245 
     | 
    
         | 
| 
       249 
     | 
    
         
            -
                     
     | 
| 
      
 246 
     | 
    
         
            +
                    # We add to both because @table_alias[use_name] is used in table(use_name)
         
     | 
| 
      
 247 
     | 
    
         
            +
                    # and @table_alias[use_name]
         
     | 
| 
      
 248 
     | 
    
         
            +
                    list  << alias_name
         
     | 
| 
      
 249 
     | 
    
         
            +
                    list2 << alias_name
         
     | 
| 
       250 
250 
     | 
    
         
             
                    alias_name
         
     | 
| 
       251 
251 
     | 
    
         
             
                  end
         
     | 
| 
       252 
252 
     | 
    
         | 
| 
       253 
253 
     | 
    
         
             
                  def add_alias_to_tables(table_name, alias_name, type = nil, &block)
         
     | 
| 
      
 254 
     | 
    
         
            +
                    if block_given?
         
     | 
| 
      
 255 
     | 
    
         
            +
                      on_clause = "#{block.call(alias_name)}"
         
     | 
| 
      
 256 
     | 
    
         
            +
                    end
         
     | 
| 
      
 257 
     | 
    
         
            +
                    
         
     | 
| 
       254 
258 
     | 
    
         
             
                    if type
         
     | 
| 
       255 
259 
     | 
    
         
             
                      key = "#{table_name}=#{type}=#{alias_name}"
         
     | 
| 
       256 
     | 
    
         
            -
                      
         
     | 
| 
       257 
260 
     | 
    
         
             
                      @needed_join_tables[key] ||= begin
         
     | 
| 
       258 
     | 
    
         
            -
                         
     | 
| 
       259 
     | 
    
         
            -
                        if alias_name && alias_name != table_name
         
     | 
| 
       260 
     | 
    
         
            -
                          clause << " AS #{alias_name}"
         
     | 
| 
       261 
     | 
    
         
            -
                        end
         
     | 
| 
       262 
     | 
    
         
            -
                        if block_given?
         
     | 
| 
       263 
     | 
    
         
            -
                          clause << " ON #{block.call(alias_name || table_name)}"
         
     | 
| 
       264 
     | 
    
         
            -
                        end
         
     | 
| 
      
 261 
     | 
    
         
            +
                        table_name = "#{type.to_s.upcase} JOIN #{table_name}"
         
     | 
| 
       265 
262 
     | 
    
         
             
                        joins = (@join_tables[main_table] ||= [])
         
     | 
| 
       266 
     | 
    
         
            -
                         
     | 
| 
      
 263 
     | 
    
         
            +
                        on_clause = on_clause ? " ON #{on_clause}" : ''
         
     | 
| 
      
 264 
     | 
    
         
            +
                        joins << (alias_name ? "#{table_name} AS #{alias_name}#{on_clause}" : "#{table_name}#{on_clause}")
         
     | 
| 
       267 
265 
     | 
    
         
             
                      end
         
     | 
| 
       268 
     | 
    
         
            -
                      return
         
     | 
| 
      
 266 
     | 
    
         
            +
                      return alias_name
         
     | 
| 
      
 267 
     | 
    
         
            +
                    end
         
     | 
| 
      
 268 
     | 
    
         
            +
                    
         
     | 
| 
      
 269 
     | 
    
         
            +
                    if on_clause && @tables.empty?
         
     | 
| 
      
 270 
     | 
    
         
            +
                      # NO JOIN
         
     | 
| 
      
 271 
     | 
    
         
            +
                      @where << on_clause
         
     | 
| 
      
 272 
     | 
    
         
            +
                      on_clause = ''
         
     | 
| 
      
 273 
     | 
    
         
            +
                    elsif on_clause
         
     | 
| 
      
 274 
     | 
    
         
            +
                      on_clause = " ON #{on_clause}"
         
     | 
| 
       269 
275 
     | 
    
         
             
                    end
         
     | 
| 
       270 
276 
     | 
    
         | 
| 
       271 
277 
     | 
    
         
             
                    if alias_name != table_name
         
     | 
| 
       272 
     | 
    
         
            -
                      @tables << "#{table_name} AS #{alias_name}"
         
     | 
| 
      
 278 
     | 
    
         
            +
                      @tables << "#{table_name} AS #{alias_name}#{on_clause}"
         
     | 
| 
       273 
279 
     | 
    
         
             
                    else
         
     | 
| 
       274 
     | 
    
         
            -
                      @tables << table_name
         
     | 
| 
      
 280 
     | 
    
         
            +
                      @tables << "#{table_name}#{on_clause}"
         
     | 
| 
       275 
281 
     | 
    
         
             
                    end
         
     | 
| 
      
 282 
     | 
    
         
            +
                    
         
     | 
| 
      
 283 
     | 
    
         
            +
                    alias_name
         
     | 
| 
       276 
284 
     | 
    
         
             
                  end
         
     | 
| 
       277 
285 
     | 
    
         | 
| 
       278 
286 
     | 
    
         
             
                  def build_statement(type = :find)
         
     | 
| 
         @@ -314,7 +322,7 @@ module QueryBuilder 
     | 
|
| 
       314 
322 
     | 
    
         
             
                      end
         
     | 
| 
       315 
323 
     | 
    
         
             
                    end
         
     | 
| 
       316 
324 
     | 
    
         | 
| 
       317 
     | 
    
         
            -
                    "SELECT#{distinct} #{(@select || ["#{main_table}.*"]).join(',')} FROM #{table_list.flatten.sort.join(' 
     | 
| 
      
 325 
     | 
    
         
            +
                    "SELECT#{distinct} #{(@select || ["#{main_table}.*"]).join(',')} FROM #{table_list.flatten.sort.join(' JOIN ')}" + (@where == [] ? '' : " WHERE #{filter}") + group.to_s + @having.to_s + @order.to_s + @limit.to_s + @offset.to_s
         
     | 
| 
       318 
326 
     | 
    
         
             
                  end
         
     | 
| 
       319 
327 
     | 
    
         | 
| 
       320 
328 
     | 
    
         
             
                  def count_statement
         
     | 
| 
         @@ -338,7 +346,13 @@ module QueryBuilder 
     | 
|
| 
       338 
346 
     | 
    
         
             
                      count_on = "COUNT(*)"
         
     | 
| 
       339 
347 
     | 
    
         
             
                    end
         
     | 
| 
       340 
348 
     | 
    
         | 
| 
       341 
     | 
    
         
            -
                    "SELECT #{count_on} FROM #{table_list.flatten.sort.join(' 
     | 
| 
      
 349 
     | 
    
         
            +
                    sql = "SELECT #{count_on} FROM #{table_list.flatten.sort.join(' JOIN ')}" + (@where == [] ? '' : " WHERE #{filter}")
         
     | 
| 
      
 350 
     | 
    
         
            +
                    if @having then
         
     | 
| 
      
 351 
     | 
    
         
            +
                      # We need the group clause in case the query uses MIN or MAX.
         
     | 
| 
      
 352 
     | 
    
         
            +
                      sql = "SELECT COUNT(*) FROM (#{sql}#{@group}#{@having}) AS BASE"
         
     | 
| 
      
 353 
     | 
    
         
            +
                    end
         
     | 
| 
      
 354 
     | 
    
         
            +
             
     | 
| 
      
 355 
     | 
    
         
            +
                    sql
         
     | 
| 
       342 
356 
     | 
    
         
             
                  end
         
     | 
| 
       343 
357 
     | 
    
         | 
| 
       344 
358 
     | 
    
         
             
                  def get_connection
         
     | 
    
        data/querybuilder.gemspec
    CHANGED
    
    | 
         @@ -5,11 +5,11 @@ 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            Gem::Specification.new do |s|
         
     | 
| 
       7 
7 
     | 
    
         
             
              s.name = %q{querybuilder}
         
     | 
| 
       8 
     | 
    
         
            -
              s.version = "1.1 
     | 
| 
      
 8 
     | 
    
         
            +
              s.version = "1.2.1"
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         
     | 
| 
       11 
11 
     | 
    
         
             
              s.authors = ["Gaspard Bucher"]
         
     | 
| 
       12 
     | 
    
         
            -
              s.date = %q{ 
     | 
| 
      
 12 
     | 
    
         
            +
              s.date = %q{2013-03-11}
         
     | 
| 
       13 
13 
     | 
    
         
             
              s.description = %q{QueryBuilder is an interpreter for the "pseudo sql" language. This language
         
     | 
| 
       14 
14 
     | 
    
         
             
                can be used for two purposes:
         
     | 
| 
       15 
15 
     | 
    
         | 
    
        data/test/querybuilder/basic.yml
    CHANGED
    
    | 
         @@ -16,8 +16,8 @@ objects_in_site: 
     | 
|
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
            recipients:
         
     | 
| 
       18 
18 
     | 
    
         
             
              sxp: '[:query, [:relation, "recipients"]]'
         
     | 
| 
       19 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
       20 
     | 
    
         
            -
              sql: "SELECT objects.* FROM links 
     | 
| 
      
 19 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects WHERE objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?}, id]"
         
     | 
| 
      
 20 
     | 
    
         
            +
              sql: "SELECT objects.* FROM links JOIN objects WHERE objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = 123"
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
            letters_in_project:
         
     | 
| 
       23 
23 
     | 
    
         
             
              sxp: '[:query, [:scope, [:relation, "letters"], "project"]]'
         
     | 
| 
         @@ -33,7 +33,7 @@ order_single_table: 
     | 
|
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
            order_many_tables:
         
     | 
| 
       35 
35 
     | 
    
         
             
              src: "recipients order by name"
         
     | 
| 
       36 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 36 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects WHERE objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ? ORDER BY objects.name}, id]"
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
            order_many_params:
         
     | 
| 
       39 
39 
     | 
    
         
             
              src: "objects in project order by name, id desc"
         
     | 
| 
         @@ -70,12 +70,12 @@ paginate: 
     | 
|
| 
       70 
70 
     | 
    
         
             
            recipients_or_objects:
         
     | 
| 
       71 
71 
     | 
    
         
             
              src: recipients or objects
         
     | 
| 
       72 
72 
     | 
    
         
             
              sxp: '[:query, [:clause_or, [:relation, "recipients"], [:relation, "objects"]]]'
         
     | 
| 
       73 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 73 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects WHERE ((objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?) OR (objects.parent_id = ? AND links.id = 0)) GROUP BY objects.id}, id, id]"
         
     | 
| 
       74 
74 
     | 
    
         | 
| 
       75 
75 
     | 
    
         
             
            recipients_or_objects_or_letters:
         
     | 
| 
       76 
76 
     | 
    
         
             
              src: recipients or objects or letters
         
     | 
| 
       77 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
       78 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 77 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects WHERE ((objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?) OR (links.id = 0 AND objects.parent_id = ?) OR (links.id = 0 AND objects.kpath LIKE 'NNL%' AND objects.parent_id = ?)) GROUP BY objects.id}, id, id, id]"
         
     | 
| 
      
 78 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects WHERE ((objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?) OR (objects.parent_id = ? AND links.id = 0) OR (objects.kpath LIKE 'NNL%' AND objects.parent_id = ? AND links.id = 0)) GROUP BY objects.id}, id, id, id]"
         
     | 
| 
       79 
79 
     | 
    
         | 
| 
       80 
80 
     | 
    
         
             
            or_clause_with_filter:
         
     | 
| 
       81 
81 
     | 
    
         
             
              src: "(recipients where name = 'foo') or objects"
         
     | 
| 
         @@ -41,13 +41,13 @@ it_should_not_use_the_first_table_as_main: 
     | 
|
| 
       41 
41 
     | 
    
         
             
              context:
         
     | 
| 
       42 
42 
     | 
    
         
             
                custom_query_group: test
         
     | 
| 
       43 
43 
     | 
    
         
             
              src: "two_table where x = '4' and name like 'b%'"
         
     | 
| 
       44 
     | 
    
         
            -
              res: "%Q{SELECT x AS x,IF(table_one.y,table_one.y,table_two.z) AS y,table_two.name FROM table_one 
     | 
| 
      
 44 
     | 
    
         
            +
              res: "%Q{SELECT x AS x,IF(table_one.y,table_one.y,table_two.z) AS y,table_two.name FROM table_one JOIN table_two WHERE (x) = '4' AND table_one.name LIKE 'b%'}"
         
     | 
| 
       45 
45 
     | 
    
         | 
| 
       46 
46 
     | 
    
         
             
            it_should_use_main_table_as_main:
         
     | 
| 
       47 
47 
     | 
    
         
             
              context:
         
     | 
| 
       48 
48 
     | 
    
         
             
                custom_query_group: test
         
     | 
| 
       49 
49 
     | 
    
         
             
              src: "two_table_main where name = '4'"
         
     | 
| 
       50 
     | 
    
         
            -
              res: "%Q{SELECT x FROM foo 
     | 
| 
      
 50 
     | 
    
         
            +
              res: "%Q{SELECT x FROM foo JOIN table_one JOIN table_two WHERE foo.name = '4'}"
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
52 
     | 
    
         
             
            it_should_limit_the_entries:
         
     | 
| 
       53 
53 
     | 
    
         
             
              context:
         
     | 
| 
         @@ -15,15 +15,15 @@ not_equal_alt: 
     | 
|
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
            recipients_where_kpath:
         
     | 
| 
       17 
17 
     | 
    
         
             
              src: "recipients where kpath like 'NRCC%'"
         
     | 
| 
       18 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 18 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects WHERE objects.kpath LIKE 'NRCC%' AND objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?}, id]"
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
20 
     | 
    
         
             
            hand_made_class_filter:
         
     | 
| 
       21 
21 
     | 
    
         
             
              src: "recipients where kpath like 'NRCC%'"
         
     | 
| 
       22 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 22 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects WHERE objects.kpath LIKE 'NRCC%' AND objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?}, id]"
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
24 
     | 
    
         
             
            better_class_filter:
         
     | 
| 
       25 
25 
     | 
    
         
             
              src: "recipients where class = 'Client'"
         
     | 
| 
       26 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 26 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects WHERE objects.kpath LIKE ? AND objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ?}, \"NRCC%\", id]"
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
            like_filter_with_scope:
         
     | 
| 
       29 
29 
     | 
    
         
             
              src: "letters where name like 'a%' in site"
         
     | 
| 
         @@ -41,7 +41,7 @@ letters_group_by_name: 
     | 
|
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
            recipients_group_by_name:
         
     | 
| 
       43 
43 
     | 
    
         
             
              sxp: '[:query, [:group, [:relation, "recipients"], [:field, "name"]]]'
         
     | 
| 
       44 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 44 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects WHERE objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ? GROUP BY objects.name}, id]"
         
     | 
| 
       45 
45 
     | 
    
         | 
| 
       46 
46 
     | 
    
         
             
            custom_query_having:
         
     | 
| 
       47 
47 
     | 
    
         
             
              context:
         
     | 
| 
         @@ -5,4 +5,4 @@ simple: 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            having_order:
         
     | 
| 
       7 
7 
     | 
    
         
             
              src: "recipients from letters select amount.sum as tot_amount group by id having tot_amount > 2000"
         
     | 
| 
       8 
     | 
    
         
            -
              res: "[%Q{SELECT objects.*,SUM(ob1.amount) AS \"tot_amount\" FROM links 
     | 
| 
      
 8 
     | 
    
         
            +
              res: "[%Q{SELECT objects.*,SUM(ob1.amount) AS \"tot_amount\" FROM links JOIN objects JOIN objects AS ob1 WHERE objects.id = links.target_id AND links.relation_id = 4 AND links.source_id = ob1.id AND ob1.kpath LIKE 'NNL%' AND ob1.parent_id = ? GROUP BY objects.id HAVING \"tot_amount\" > 2000}, id]"
         
     | 
    
        data/test/querybuilder/joins.yml
    CHANGED
    
    | 
         @@ -1,23 +1,23 @@ 
     | 
|
| 
       1 
1 
     | 
    
         | 
| 
       2 
2 
     | 
    
         
             
            icons_from_recipients:
         
     | 
| 
       3 
3 
     | 
    
         
             
              sxp: '[:query, [:from, [:relation, "icons"], [:relation, "recipients"]]]'
         
     | 
| 
       4 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 4 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN links AS li1 JOIN objects JOIN objects AS ob1 WHERE objects.id = li1.source_id AND li1.relation_id = 5 AND li1.target_id = ob1.id AND ob1.id = links.target_id AND links.relation_id = 4 AND links.source_id = ? GROUP BY objects.id}, id]"
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            icons_from_recipients_from_letters:
         
     | 
| 
       7 
7 
     | 
    
         
             
              sxp: '[:query, [:from, [:from, [:relation, "icons"], [:relation, "recipients"]], [:relation, "letters"]]]'
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
            letters_from_recipients:
         
     | 
| 
       10 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 10 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects JOIN objects AS ob1 WHERE objects.kpath LIKE 'NNL%' AND objects.parent_id = ob1.id AND ob1.id = links.target_id AND links.relation_id = 4 AND links.source_id = ? GROUP BY objects.id}, id]"
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
            objects_from_recipients:
         
     | 
| 
       13 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM links 
     | 
| 
      
 13 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM links JOIN objects JOIN objects AS ob1 WHERE objects.parent_id = ob1.id AND ob1.id = links.target_id AND links.relation_id = 4 AND links.source_id = ? GROUP BY objects.id}, id]"
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
            parent_from_parent:
         
     | 
| 
       16 
16 
     | 
    
         
             
              sxp: '[:query, [:from, [:relation, "parent"], [:relation, "parent"]]]'
         
     | 
| 
       17 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM objects 
     | 
| 
      
 17 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM objects JOIN objects AS ob1 WHERE objects.id = ob1.parent_id AND ob1.id = ? GROUP BY objects.id}, parent_id]"
         
     | 
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
            children_from_objects_in_project:
         
     | 
| 
       20 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM objects 
     | 
| 
      
 20 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM objects JOIN objects AS ob1 WHERE objects.parent_id = ob1.id AND ob1.project_id = ? GROUP BY objects.id}, project_id]"
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
            tags:
         
     | 
| 
       23 
23 
     | 
    
         
             
              sxp: '[:query, [:relation, "tags"]]'
         
     | 
| 
         @@ -34,9 +34,9 @@ complex_from_with_scopes_and_typed_scope: 
     | 
|
| 
       34 
34 
     | 
    
         | 
| 
       35 
35 
     | 
    
         
             
            letters_in_project_from_letters:
         
     | 
| 
       36 
36 
     | 
    
         
             
              sxp: '[:query, [:from, [:scope, [:relation, "letters"], "project"], [:relation, "letters"]]]'
         
     | 
| 
       37 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM objects 
     | 
| 
      
 37 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM objects JOIN objects AS ob1 WHERE objects.kpath LIKE 'NNL%' AND objects.project_id = ob1.id AND ob1.kpath LIKE 'NNL%' AND ob1.parent_id = ? GROUP BY objects.id}, id]"
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
39 
     | 
    
         
             
            letters_in_project_from_letters_group_by:
         
     | 
| 
       40 
40 
     | 
    
         
             
              src: "letters in project from letters group by name,id"
         
     | 
| 
       41 
41 
     | 
    
         
             
              sxp: '[:query, [:group, [:from, [:scope, [:relation, "letters"], "project"], [:relation, "letters"]], [:field, "name"], [:field, "id"]]]'
         
     | 
| 
       42 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM objects 
     | 
| 
      
 42 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM objects JOIN objects AS ob1 WHERE objects.kpath LIKE 'NNL%' AND objects.project_id = ob1.id AND ob1.kpath LIKE 'NNL%' AND ob1.parent_id = ? GROUP BY objects.name, objects.id}, id]"
         
     | 
    
        data/test/querybuilder/mixed.yml
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            users_from_objects:
         
     | 
| 
       2 
2 
     | 
    
         
             
              sxp: '[:query, [:from, [:relation, "users"], [:relation, "objects"]]]'
         
     | 
| 
       3 
     | 
    
         
            -
              res: "TestUser: [%Q{SELECT users.* FROM objects AS ob1 
     | 
| 
      
 3 
     | 
    
         
            +
              res: "TestUser: [%Q{SELECT users.* FROM objects AS ob1 JOIN users WHERE users.node_id = ob1.id AND ob1.parent_id = ? GROUP BY users.id ORDER BY users.name ASC, users.first_name ASC}, id]"
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            users_where_name_from_objects:
         
     | 
| 
       6 
6 
     | 
    
         
             
              src: "users where name eq 'bob' from objects"
         
     | 
| 
       7 
     | 
    
         
            -
              res: "TestUser: [%Q{SELECT users.* FROM objects AS ob1 
     | 
| 
      
 7 
     | 
    
         
            +
              res: "TestUser: [%Q{SELECT users.* FROM objects AS ob1 JOIN users WHERE users.name = 'bob' AND users.node_id = ob1.id AND ob1.parent_id = ? GROUP BY users.id ORDER BY users.name ASC, users.first_name ASC}, id]"
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
            objects_from_users_from_objects:
         
     | 
| 
       10 
10 
     | 
    
         
             
              src: "objects from users where name = 'foo' from objects where event_at > REF_DATE order by event_at asc"
         
     | 
| 
       11 
     | 
    
         
            -
              res: "[%Q{SELECT objects.* FROM objects 
     | 
| 
      
 11 
     | 
    
         
            +
              res: "[%Q{SELECT objects.* FROM objects JOIN objects AS ob1 JOIN users AS us1 WHERE objects.id = us1.node_id AND us1.name = 'foo' AND us1.node_id = ob1.id AND ob1.event_at > now() AND ob1.parent_id = ? GROUP BY objects.id ORDER BY objects.event_at ASC}, id]"
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
            users:
         
     | 
| 
       14 
14 
     | 
    
         
             
              res: "TestUser: [%Q{SELECT users.* FROM users WHERE users.node_id = ? ORDER BY users.name ASC, users.first_name ASC}, id]"
         
     | 
    
        data/test/querybuilder_test.rb
    CHANGED
    
    | 
         @@ -39,7 +39,7 @@ class DummyQueryBuilder < Test::Unit::TestCase 
     | 
|
| 
       39 
39 
     | 
    
         
             
                end
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
                should 'not overwrite defaults before last' do
         
     | 
| 
       42 
     | 
    
         
            -
                  assert_equal '%Q{SELECT objects.* FROM objects 
     | 
| 
      
 42 
     | 
    
         
            +
                  assert_equal '%Q{SELECT objects.* FROM objects JOIN objects AS ob1 WHERE objects.parent_id = ob1.id GROUP BY objects.id}', subject.new('objects from objects', :default => {:scope => 'site'}).query.to_s
         
     | 
| 
       43 
43 
     | 
    
         
             
                end
         
     | 
| 
       44 
44 
     | 
    
         
             
              end
         
     | 
| 
       45 
45 
     | 
    
         | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,13 +1,13 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification 
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: querybuilder
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version 
         
     | 
| 
       4 
     | 
    
         
            -
              hash:  
     | 
| 
      
 4 
     | 
    
         
            +
              hash: 29
         
     | 
| 
       5 
5 
     | 
    
         
             
              prerelease: 
         
     | 
| 
       6 
6 
     | 
    
         
             
              segments: 
         
     | 
| 
       7 
7 
     | 
    
         
             
              - 1
         
     | 
| 
      
 8 
     | 
    
         
            +
              - 2
         
     | 
| 
       8 
9 
     | 
    
         
             
              - 1
         
     | 
| 
       9 
     | 
    
         
            -
               
     | 
| 
       10 
     | 
    
         
            -
              version: 1.1.4
         
     | 
| 
      
 10 
     | 
    
         
            +
              version: 1.2.1
         
     | 
| 
       11 
11 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       12 
12 
     | 
    
         
             
            authors: 
         
     | 
| 
       13 
13 
     | 
    
         
             
            - Gaspard Bucher
         
     | 
| 
         @@ -15,7 +15,7 @@ autorequire: 
     | 
|
| 
       15 
15 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       16 
16 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
            date:  
     | 
| 
      
 18 
     | 
    
         
            +
            date: 2013-03-11 00:00:00 +01:00
         
     | 
| 
       19 
19 
     | 
    
         
             
            default_executable: 
         
     | 
| 
       20 
20 
     | 
    
         
             
            dependencies: 
         
     | 
| 
       21 
21 
     | 
    
         
             
            - !ruby/object:Gem::Dependency 
         
     |