lib/torque/postgresql/auxiliary_statement.rb in torque-postgresql-0.1.2 vs lib/torque/postgresql/auxiliary_statement.rb in torque-postgresql-0.1.3

- old
+ new

@@ -58,11 +58,11 @@ base.name end # Get the arel version of the statement table def table - @table ||= Arel::Table.new(table_name) + @table ||= ::Arel::Table.new(table_name) end # Get the name of the table of the configurated statement def table_name @table_name ||= self.name.demodulize.split('_').first.underscore @@ -78,13 +78,15 @@ @query_table ||= query.arel_table end # Project a column on a given table, or use the column table def project(column, arel_table = nil) - if column.to_s.include?('.') + if column.respond_to?(:as) + return column + elsif column.to_s.include?('.') table_name, column = column.to_s.split('.') - arel_table = Arel::Table.new(table_name) + arel_table = ::Arel::Table.new(table_name) end arel_table ||= table arel_table[column.to_s] end @@ -100,49 +102,12 @@ defined?(@query) && @query end # Setup the class def setup! - # attributes key: - # Provides a map of attributes to be exposed to the main query. - # - # For instace, if the statement query has an 'id' column that you - # want it to be accessed on the main query as 'item_id', - # you can use: - # attributes id: :item_id - # - # If its statement has more tables, and you want to expose those - # fields, then: - # attributes 'table.name': :item_name - # - # join_type key: - # Changes the type of the join and set the constraints - # - # The left side of the hash is the source table column, the right - # side is the statement table column, now it's only accepting '=' - # constraints - # join id: :user_id - # join id: :'user.id' - # join 'post.id': :'user.last_post_id' - # - # It's possible to change the default type of join - # join :left, id: :user_id - # - # join key: - # Changes the type of the join - # - # query key: - # Save the query command to be performand - # - # requires key: - # Indicates dependencies with another statements - # - # polymorphic key: - # Indicates a polymorphic relationship, with will affect the way the - # auto join works, by giving a polymorphic connection settings = Settings.new(self) - @config.call(settings) + settings.instance_exec(settings, &@config) @join_type = settings.join_type || :inner @requires = Array[settings.requires].flatten.compact @query = settings.query @@ -230,39 +195,43 @@ exposed_attributes + @select.values.map(&method(:project)) end # Build the statement on the given arel and return the WITH statement def build_arel(arel, base) - list = [] - - # Process dependencies - if requires.present? - requires.each do |dependent| - next if base.auxiliary_statements.key?(dependent) - - instance = AuxiliaryStatement.instantiate(dependent, base) - base.auxiliary_statements[dependent] = instance - list << instance.build_arel(arel, base) - end - end - # Build the join for this statement arel.join(table, arel_join).on(*join_columns) # Return the subquery for this statement - list << Arel::Nodes::As.new(table, mount_query) + ::Arel::Nodes::As.new(table, mount_query) end + # Get the bound attributes from statement qeury + def bound_attributes + return [] unless relation_query?(self.class.query) + self.class.query.send(:bound_attributes) + end + + # Ensure that all the dependencies are loaded in the base relation + def ensure_dependencies!(base) + requires.each do |dependent| + next if base.auxiliary_statements.key?(dependent) + + instance = AuxiliaryStatement.instantiate(dependent, base) + instance.ensure_dependencies!(base) + base.auxiliary_statements[dependent] = instance + end + end + private # Get the class of the join on arel def arel_join case @join_type - when :inner then Arel::Nodes::InnerJoin - when :left then Arel::Nodes::OuterJoin - when :right then Arel::Nodes::RightOuterJoin - when :full then Arel::Nodes::FullOuterJoin + when :inner then ::Arel::Nodes::InnerJoin + when :left then ::Arel::Nodes::OuterJoin + when :right then ::Arel::Nodes::RightOuterJoin + when :full then ::Arel::Nodes::FullOuterJoin else raise ArgumentError, <<-MSG.strip The '#{@join_type}' is not implemented as a join type. MSG end @@ -270,22 +239,23 @@ # Mount the query base on it's class def mount_query klass = self.class query = klass.query - uses = @uses.map(&klass.parent.connection.method(:quote)) + uses = @uses # Call a proc to get the query if query.respond_to?(:call) query = query.call(*uses) uses = [] end # Prepare the query depending on its type if query.is_a?(String) - Arel::Nodes::SqlLiteral.new("(#{query})" % uses) + uses.map!(&klass.parent.connection.method(:quote)) + ::Arel::Nodes::SqlLiteral.new("(#{query})" % uses) elsif relation_query?(query) - query.select(*select_columns).send(:build_arel) + query.select(*select_columns).arel else raise ArgumentError, <<-MSG.strip Only String and ActiveRecord::Base objects are accepted as query objects, #{query.class.name} given for #{self.class.name}. MSG