ActiveRecord Refactoring Project
February 26, 2007 § Leave a comment
I am excited that Zach Dennis has taken up last year’s cause of ActiveRecord Refactoring, since I never made much progress on my ActiveData efforts. Still, to help him out I’ve posted my pre-alpha ActiveData code, which builds on my earlier non-SQL ActiveRecord. I’ve pasted some excerpts below (Read More).
module ActiveData module ConnectionAdapters #:nodoc: class AbstractAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter include Query end end end # ONLY PARTIALLY IMPLEMENTED module ActiveRecord module ConnectionAdapters # :nodoc: module Query # Define services for creating queries for this connection # Defaults to simply creating SQL strings # Return query object for this connection def new_query() return QueryGenerator(self) end class QueryGenerator def initialize(connection) @connection = connection @query ="" end # Map all database statements directly # That way, adapters default to the simplest possible implementation # But, custom adapters can override this query to do special-purpose things def execute(action, log_msg) case action when :select_all then @connection.select_all(@query,log_msg) when :select_one then @connection.select_one(@query,log_msg) when :update then @connection.update(@query,log_msg) when :delete then @connection.delete(@query,log_msg) end end def insert(log_msg) @connection.insert(@query,log_msg) end # Query Construction def add(verb, noun) @query << " #{verb} #{noun}" end #.... end # class end # module Query end end module ActiveData # ActiveRecord for non-SQL Data Sources class Base < ActiveRecord::Base # Override SQL-creating data methods to instead use # generic Query objects to query/create/update other datastores # Works like find(:all), but requires a complete SQL string # (in this case, an initialized Query object) def find_by_sql(sql) sql = sanitize_sql(sql) sql.execute(:select_all, "#{name} Load").collect! { |record| instantiate(record) } end def update_all(updates, conditions = nil) sql = connection.new_query() sql.add("UPDATE", table_name) sql.add("SET", sanitize_sql(updates)) add_conditions!(sql, conditions) sql.execute(:update, "#{name} Update") end #... def count(conditions = nil, joins = nil) sql = connection.new_query() sql.add("SELECT", "COUNT(*)") sql.add("FROM", table_name) sql.add(nil, joins) if joins add_conditions!(sql, conditions) count_by_sql(sql) end def count_by_sql(sql) sql = sanitize_conditions(sql) sql.execute(:select_value, "#{name} Count").to_i end def construct_finder_sql(options) sql=connection.new_query() sql.add("SELECT",options[:select] || '*') sql.add("FROM",table_name) add_joins!(sql, options) add_conditions!(sql, options[:conditions]) sql.add("GROUP BY",options[:group]) if options[:group] sql.add("ORDER BY",options[:order]) if options[:order] add_limit!(sql, options) sql end def add_limit!(sql, options) options[:limit] ||= scope(:find, :limit) options[:offset] ||= scope(:find, :offset) sql.add_limit_offset!(options) end def add_joins!(sql, options) join = scope(:find, :joins) || options[:joins] sql.add_join(join) if join end # Adds a sanitized version of +conditions+ to the +sql+ string. # Note that the passed-in +sql+ string is changed. def add_conditions!(sql, conditions) segments = [scope(:find, :conditions)] segments << sanitize_sql(conditions) unless conditions.nil? segments << type_condition unless descends_from_active_record? segments.compact! sql.add_array("WHERE",segments) unless segments.empty? # need to explicitly join with "AND" sql << "WHERE (#{segments.join(") AND (")}) " unless segments.empty? end end # class Base end # module ActiveData
Leave a Reply