From: Tom Clegg Date: Fri, 14 Mar 2014 14:17:46 +0000 (-0400) Subject: Merge branch 'master' into 2257-inequality-conditions X-Git-Tag: 1.1.0~2709^2~97^2^2~2 X-Git-Url: https://git.arvados.org/arvados.git/commitdiff_plain/35336cd73e444534cb2eda20e3730464cc4e6553?hp=-c Merge branch 'master' into 2257-inequality-conditions --- 35336cd73e444534cb2eda20e3730464cc4e6553 diff --combined services/api/app/controllers/application_controller.rb index 8ed554f8ca,7c10c8425d..2d37dc18cd --- a/services/api/app/controllers/application_controller.rb +++ b/services/api/app/controllers/application_controller.rb @@@ -10,7 -10,6 +10,7 @@@ class ApplicationController < ActionCon before_filter :catch_redirect_hint before_filter :load_where_param, :only => :index + before_filter :load_filters_param, :only => :index before_filter :find_objects_for_index, :only => :index before_filter :find_object_by_uuid, :except => [:index, :create, :render_error, @@@ -39,7 -38,7 +39,7 @@@ if @object.save show else - render_error "Save failed" + raise "Save failed" end end @@@ -50,7 -49,7 +50,7 @@@ if @object.update_attributes attrs_to_update show else - render_error "Update failed" + raise "Update failed" end end @@@ -88,7 -87,9 +88,9 @@@ def render_error(e) logger.error e.inspect - logger.error e.backtrace.collect { |x| x + "\n" }.join('') if e.backtrace + if e.respond_to? :backtrace and e.backtrace + logger.error e.backtrace.collect { |x| x + "\n" }.join('') + end if @object and @object.errors and @object.errors.full_messages and not @object.errors.full_messages.empty? errors = @object.errors.full_messages else @@@ -112,63 -113,16 +114,63 @@@ @where = params[:where] elsif params[:where].is_a? String begin - @where = Oj.load(params[:where], symbol_keys: true) + @where = Oj.load(params[:where]) + raise unless @where.is_a? Hash rescue raise ArgumentError.new("Could not parse \"where\" param as an object") end end + @where = @where.with_indifferent_access + end + + def load_filters_param + if params[:filters].is_a? Array + @filters = params[:filters] + elsif params[:filters].is_a? String + begin + @filters = Oj.load params[:filters] + raise unless @filters.is_a? Array + rescue + raise ArgumentError.new("Could not parse \"filters\" param as an array") + end + end end def find_objects_for_index @objects ||= model_class.readable_by(current_user) - if !@where.empty? + apply_where_limit_order_params + end + + def apply_where_limit_order_params + if @filters.is_a? Array and @filters.any? + cond_out = [] + param_out = [] + @filters.each do |attr, operator, operand| + if !model_class.searchable_columns.index attr.to_s + raise ArgumentError.new("Invalid attribute '#{attr}' in condition") + end + case operator.downcase + when '=', '<', '<=', '>', '>=', 'like' + if operand.is_a? String + cond_out << "#{table_name}.#{attr} #{operator} ?" + if operator.match(/[<=>]/) and + model_class.attribute_column(attr).type == :datetime + operand = Time.parse operand + end + param_out << operand + end + when 'in' + if operand.is_a? Array + cond_out << "#{table_name}.#{attr} IN (?)" + param_out << operand + end + end + end + if cond_out.any? + @objects = @objects.where(cond_out.join(' AND '), *param_out) + end + end + if @where.is_a? Hash and @where.any? conditions = ['1=1'] @where.each do |attr,value| if attr == :any @@@ -313,7 -267,7 +315,7 @@@ if supplied_token api_client_auth = ApiClientAuthorization. includes(:api_client, :user). - where('api_token=? and (expires_at is null or expires_at > now())', supplied_token). + where('api_token=? and (expires_at is null or expires_at > CURRENT_TIMESTAMP)', supplied_token). first if api_client_auth.andand.user session[:user_id] = api_client_auth.user.id @@@ -432,7 -386,6 +434,7 @@@ def self._index_requires_parameters { + filters: { type: 'array', required: false }, where: { type: 'object', required: false }, order: { type: 'string', required: false } } @@@ -444,13 -397,15 +446,15 @@@ end def render *opts - response = opts.first[:json] - if response.is_a?(Hash) && - params[:_profile] && - Thread.current[:request_starttime] - response[:_profile] = { - request_time: Time.now - Thread.current[:request_starttime] - } + if opts.first + response = opts.first[:json] + if response.is_a?(Hash) && + params[:_profile] && + Thread.current[:request_starttime] + response[:_profile] = { + request_time: Time.now - Thread.current[:request_starttime] + } + end end super *opts end diff --combined services/api/app/models/arvados_model.rb index 9475f0dd1d,c89efdf404..84bdf95763 --- a/services/api/app/models/arvados_model.rb +++ b/services/api/app/models/arvados_model.rb @@@ -40,16 -40,12 +40,16 @@@ class ArvadosModel < ActiveRecord::Bas def self.searchable_columns self.columns.collect do |col| - if [:string, :text].index(col.type) && col.name != 'owner_uuid' + if [:string, :text, :datetime].index(col.type) && col.name != 'owner_uuid' col.name end end.compact end + def self.attribute_column attr + self.columns.select { |col| col.name == attr.to_s }.first + end + def eager_load_associations self.class.columns.each do |col| re = col.name.match /^(.*)_kind$/ @@@ -140,7 -136,7 +140,7 @@@ def update_modified_by_fields self.created_at ||= Time.now - self.owner_uuid ||= current_default_owner + self.owner_uuid ||= current_default_owner if self.respond_to? :owner_uuid= self.modified_at = Time.now self.modified_by_user_uuid = current_user ? current_user.uuid : nil self.modified_by_client_uuid = current_api_client ? current_api_client.uuid : nil