lib/dm-tokyo-adapter/query.rb in shanna-dm-tokyo-adapter-0.2.1 vs lib/dm-tokyo-adapter/query.rb in shanna-dm-tokyo-adapter-0.3.0

- old
+ new

@@ -16,58 +16,65 @@ include DataMapper::Query::Conditions def initialize(connection, query) assert_kind_of 'connection', connection, Rufus::Tokyo::Table assert_kind_of 'query', query, DataMapper::Query - @connection, @query, @native = connection, query, true + @connection, @query, @native = connection, query, [] end #-- - # TODO: Log when a query cannot be performed natively by TC. - # TODO: Use native sorting if there is only a single order condition. # TODO: connection[] if I have everything I need to fetch by the primary key. def read records = @connection.query do |statements| if @query.conditions.kind_of?(OrOperation) - @native = false + fail_native("Operation '#{@query.conditions.slug}'.") else @query.conditions.each do |condition| condition_statement(statements, condition) end end - statements.no_pk - if @native - statements.limit(@query.limit) if @query.limit - # TODO: Native sorting when only one order field. + if native? && !@query.order.empty? + sort_statement(statements, @query.order) end + + statements.limit(@query.limit) if native? && @query.limit + statements.no_pk end - # Typecast return values. records.each do |record| @query.fields.each do |property| field = property.field record[field] = property.typecast(record[field]) end end + return records if native? + # TODO: Move log entry out to adapter sublcass and use #name? + DataMapper.logger.warn( + "TokyoAdapter: No native TableQuery support for conditions: #{@native.join(' ')}" + ) @query.filter_records(records) end + def native? + @native.empty? + end + private def condition_statement(statements, conditions, affirmative = true) case conditions when AbstractOperation then operation_statement(statements, conditions, affrimative) when AbstractComparison then comparison_statement(statements, conditions, affirmative) end end def operation_statement(statements, operation, affirmative = true) case operation - when OrOperation then @native = false when NotOperation then condition_statement(statements, operation.first, !affirmative) when AndOperation then operation.each{|op| condition_statement(statements, op, affirmative)} + else fail_native("Operation '#{operation.slug}'.") end end def comparison_statement(statements, comparison, affirmative = true) value = comparison.value @@ -89,20 +96,34 @@ when LikeComparison then :regex when GreaterThanComparison then :gt when LessThanComparison then :lt when GreaterThanOrEqualToComparison then :gte when LessThanOrEqualToComparison then :lte + else fail_native("Comparison #{comparison.slug}'.") && return end - unless operator - @native = false - return - end statements.add(comparison.property.field, operator, quote_value(value), affirmative) end def quote_value(value) "#{value}" + end + + def sort_statement(statements, conditions) + fail_native("Multiple (#{conditions.size}) order conditions.") if conditions.size > 1 + + sort_order = conditions.first + primitive = sort_order.target.primitive + direction = case sort_order.operator + when :asc then primitive == Integer ? :numasc : :asc + when :desc then primitive == Integer ? :numdesc : :desc + end + + statements.order_by(sort_order.target.field, direction) + end + + def fail_native(why) + @native << why end end # Query end # Tokyo end # Adapters end # DataMapper