diff --git a/plugin.rb b/plugin.rb index 0b04fdd..0dd1180 100644 --- a/plugin.rb +++ b/plugin.rb @@ -65,19 +65,19 @@ after_initialize do # pg_result - the PG::Result object # duration_nanos - the query duration, in nanoseconds # explain - the query - def self.run_query(query, req_params={}, opts={}) + def self.run_query(query, req_params = {}, opts = {}) # Safety checks # see test 'doesn't allow you to modify the database #2' if query.sql =~ /;/ err = DataExplorer::ValidationError.new(I18n.t('js.errors.explorer.no_semicolons')) - return {error: err, duration_nanos: 0} + return { error: err, duration_nanos: 0 } end query_args = {} begin query_args = query.cast_params req_params rescue DataExplorer::ValidationError => e - return {error: e, duration_nanos: 0} + return { error: e, duration_nanos: 0 } end # If we don't include this, then queries with a % sign in them fail @@ -114,7 +114,7 @@ SQL if opts[:explain] explain = ActiveRecord::Base.exec_sql("-- :xxdummy \nEXPLAIN #{query.sql}", query_args) - .map { |row| row["QUERY PLAN"] }.join "\n" + .map { |row| row["QUERY PLAN"] }.join "\n" end # All done. Issue a rollback anyways, just in case @@ -131,20 +131,20 @@ SQL pg_result: result, duration_secs: time_end - time_start, explain: explain, - params_full: query_args.tap {|h| h.delete :xxdummy} + params_full: query_args.tap { |h| h.delete :xxdummy } } end def self.extra_data_pluck_fields @extra_data_pluck_fields ||= { - user: {class: User, fields: [:id, :username, :uploaded_avatar_id], serializer: BasicUserSerializer}, - badge: {class: Badge, fields: [:id, :name, :badge_type_id, :description, :icon], include: [:badge_type], serializer: SmallBadgeSerializer}, - post: {class: Post, fields: [:id, :topic_id, :post_number, :cooked, :user_id], include: [:user], serializer: SmallPostWithExcerptSerializer}, - topic: {class: Topic, fields: [:id, :title, :slug, :posts_count], serializer: BasicTopicSerializer}, - group: {class: Group, ignore: true}, - category: {class: Category, ignore: true}, - reltime: {ignore: true}, - html: {ignore: true}, + user: { class: User, fields: [:id, :username, :uploaded_avatar_id], serializer: BasicUserSerializer }, + badge: { class: Badge, fields: [:id, :name, :badge_type_id, :description, :icon], include: [:badge_type], serializer: SmallBadgeSerializer }, + post: { class: Post, fields: [:id, :topic_id, :post_number, :cooked, :user_id], include: [:user], serializer: SmallPostWithExcerptSerializer }, + topic: { class: Topic, fields: [:id, :title, :slug, :posts_count], serializer: BasicTopicSerializer }, + group: { class: Group, ignore: true }, + category: { class: Category, ignore: true }, + reltime: { ignore: true }, + html: { ignore: true }, } end @@ -200,10 +200,10 @@ SQL all_objs = object_class all_objs = all_objs.with_deleted if all_objs.respond_to? :with_deleted all_objs = all_objs - .select(support_info[:fields]) - .where(id: ids.to_a.sort) - .includes(support_info[:include]) - .order(:id) + .select(support_info[:fields]) + .where(id: ids.to_a.sort) + .includes(support_info[:include]) + .order(:id) ret[cls] = ActiveModel::ArraySerializer.new(all_objs, each_serializer: support_info[:serializer]) end @@ -346,30 +346,30 @@ SQL def self.enums @enums ||= { - :'badges.badge_type_id' => Enum.new(:gold, :silver, :bronze, start: 1), - :'category_groups.permission_type' => CategoryGroup.permission_types, - :'directory_items.period_type' => DirectoryItem.period_types, - :'groups.alias_level' => Group::ALIAS_LEVELS, - :'groups.id' => Group::AUTO_GROUPS, - :'notifications.notification_type' => Notification.types, - :'posts.cook_method' => Post.cook_methods, - :'posts.hidden_reason_id' => Post.hidden_reasons, - :'posts.post_type' => Post.types, - :'post_actions.post_action_type_id' => PostActionType.types, - :'post_action_types.id' => PostActionType.types, - :'queued_posts.state' => QueuedPost.states, - :'site_settings.data_type' => SiteSetting.types, - :'topic_users.notification_level' => TopicUser.notification_levels, - :'topic_users.notifications_reason_id' => TopicUser.notification_reasons, - :'user_histories.action' => UserHistory.actions, - :'users.trust_level' => TrustLevel.levels, + 'badges.badge_type_id': Enum.new(:gold, :silver, :bronze, start: 1), + 'category_groups.permission_type': CategoryGroup.permission_types, + 'directory_items.period_type': DirectoryItem.period_types, + 'groups.alias_level': Group::ALIAS_LEVELS, + 'groups.id': Group::AUTO_GROUPS, + 'notifications.notification_type': Notification.types, + 'posts.cook_method': Post.cook_methods, + 'posts.hidden_reason_id': Post.hidden_reasons, + 'posts.post_type': Post.types, + 'post_actions.post_action_type_id': PostActionType.types, + 'post_action_types.id': PostActionType.types, + 'queued_posts.state': QueuedPost.states, + 'site_settings.data_type': SiteSetting.types, + 'topic_users.notification_level': TopicUser.notification_levels, + 'topic_users.notifications_reason_id': TopicUser.notification_reasons, + 'user_histories.action': UserHistory.actions, + 'users.trust_level': TrustLevel.levels, }.with_indifferent_access end def self.enum_info @enum_info ||= begin enum_info = {} - enums.map do |key,enum| + enums.map do |key, enum| # https://stackoverflow.com/questions/10874356/reverse-a-hash-in-ruby enum_info[key] = Hash[enum.to_a.map(&:reverse)] end @@ -393,181 +393,181 @@ SQL def self.foreign_keys @fkey_columns ||= { - :'posts.last_editor_id' => :users, - :'posts.version' => :'post_revisions.number', + 'posts.last_editor_id': :users, + 'posts.version': :'post_revisions.number', - :'topics.featured_user1_id' => :users, - :'topics.featured_user2_id' => :users, - :'topics.featured_user3_id' => :users, - :'topics.featured_user4_id' => :users, - :'topics.featured_user5_id' => :users, + 'topics.featured_user1_id': :users, + 'topics.featured_user2_id': :users, + 'topics.featured_user3_id': :users, + 'topics.featured_user4_id': :users, + 'topics.featured_user5_id': :users, - :'users.seen_notification_id' => :notifications, - :'users.uploaded_avatar_id' => :uploads, - :'users.primary_group_id' => :groups, + 'users.seen_notification_id': :notifications, + 'users.uploaded_avatar_id': :uploads, + 'users.primary_group_id': :groups, - :'categories.latest_post_id' => :posts, - :'categories.latest_topic_id' => :topics, - :'categories.parent_category_id' => :categories, + 'categories.latest_post_id': :posts, + 'categories.latest_topic_id': :topics, + 'categories.parent_category_id': :categories, - :'badges.badge_grouping_id' => :badge_groupings, + 'badges.badge_grouping_id': :badge_groupings, - :'post_actions.related_post_id' => :posts, + 'post_actions.related_post_id': :posts, - :'color_scheme_colors.color_scheme_id' => :color_schemes, - :'color_schemes.versioned_id' => :color_schemes, + 'color_scheme_colors.color_scheme_id': :color_schemes, + 'color_schemes.versioned_id': :color_schemes, - :'incoming_links.incoming_referer_id' => :incoming_referers, - :'incoming_referers.incoming_domain_id' => :incoming_domains, + 'incoming_links.incoming_referer_id': :incoming_referers, + 'incoming_referers.incoming_domain_id': :incoming_domains, - :'post_replies.reply_id' => :posts, + 'post_replies.reply_id': :posts, - :'quoted_posts.quoted_post_id' => :posts, + 'quoted_posts.quoted_post_id': :posts, - :'topic_link_clicks.topic_link_id' => :topic_links, - :'topic_link_clicks.link_topic_id' => :topics, - :'topic_link_clicks.link_post_id' => :posts, + 'topic_link_clicks.topic_link_id': :topic_links, + 'topic_link_clicks.link_topic_id': :topics, + 'topic_link_clicks.link_post_id': :posts, - :'user_actions.target_topic_id' => :topics, - :'user_actions.target_post_id' => :posts, + 'user_actions.target_topic_id': :topics, + 'user_actions.target_post_id': :posts, - :'user_avatars.custom_upload_id' => :uploads, - :'user_avatars.gravatar_upload_id' => :uploads, + 'user_avatars.custom_upload_id': :uploads, + 'user_avatars.gravatar_upload_id': :uploads, - :'user_badges.notification_id' => :notifications, + 'user_badges.notification_id': :notifications, - :'user_profiles.card_image_badge_id' => :badges, + 'user_profiles.card_image_badge_id': :badges, }.with_indifferent_access end def self.fkey_defaults @fkey_defaults ||= { - :user_id => :users, + user_id: :users, # :*_by_id => :users, # :*_user_id => :users, - :category_id => :categories, - :group_id => :groups, - :post_id => :posts, - :post_action_id => :post_actions, - :topic_id => :topics, - :upload_id => :uploads, + category_id: :categories, + group_id: :groups, + post_id: :posts, + post_action_id: :post_actions, + topic_id: :topics, + upload_id: :uploads, }.with_indifferent_access end def self.denormalized_columns { - :'posts.reply_count' => :post_replies, - :'posts.quote_count' => :quoted_posts, - :'posts.incoming_link_count' => :topic_links, - :'posts.word_count' => :posts, - :'posts.avg_time' => :post_timings, - :'posts.reads' => :post_timings, - :'posts.like_score' => :post_actions, + 'posts.reply_count': :post_replies, + 'posts.quote_count': :quoted_posts, + 'posts.incoming_link_count': :topic_links, + 'posts.word_count': :posts, + 'posts.avg_time': :post_timings, + 'posts.reads': :post_timings, + 'posts.like_score': :post_actions, - :'posts.like_count' => :post_actions, - :'posts.bookmark_count' => :post_actions, - :'posts.vote_count' => :post_actions, - :'posts.off_topic_count' => :post_actions, - :'posts.notify_moderators_count' => :post_actions, - :'posts.spam_count' => :post_actions, - :'posts.illegal_count' => :post_actions, - :'posts.inappropriate_count' => :post_actions, - :'posts.notify_user_count' => :post_actions, + 'posts.like_count': :post_actions, + 'posts.bookmark_count': :post_actions, + 'posts.vote_count': :post_actions, + 'posts.off_topic_count': :post_actions, + 'posts.notify_moderators_count': :post_actions, + 'posts.spam_count': :post_actions, + 'posts.illegal_count': :post_actions, + 'posts.inappropriate_count': :post_actions, + 'posts.notify_user_count': :post_actions, - :'topics.views' => :topic_views, - :'topics.posts_count' => :posts, - :'topics.reply_count' => :posts, - :'topics.incoming_link_count' => :topic_links, - :'topics.moderator_posts_count' => :posts, - :'topics.participant_count' => :posts, - :'topics.word_count' => :posts, - :'topics.last_posted_at' => :posts, - :'topics.last_post_user_idt' => :posts, - :'topics.avg_time' => :post_timings, - :'topics.highest_post_number' => :posts, - :'topics.image_url' => :posts, - :'topics.excerpt' => :posts, + 'topics.views': :topic_views, + 'topics.posts_count': :posts, + 'topics.reply_count': :posts, + 'topics.incoming_link_count': :topic_links, + 'topics.moderator_posts_count': :posts, + 'topics.participant_count': :posts, + 'topics.word_count': :posts, + 'topics.last_posted_at': :posts, + 'topics.last_post_user_idt': :posts, + 'topics.avg_time': :post_timings, + 'topics.highest_post_number': :posts, + 'topics.image_url': :posts, + 'topics.excerpt': :posts, - :'topics.like_count' => :post_actions, - :'topics.bookmark_count' => :post_actions, - :'topics.vote_count' => :post_actions, - :'topics.off_topic_count' => :post_actions, - :'topics.notify_moderators_count' => :post_actions, - :'topics.spam_count' => :post_actions, - :'topics.illegal_count' => :post_actions, - :'topics.inappropriate_count' => :post_actions, - :'topics.notify_user_count' => :post_actions, + 'topics.like_count': :post_actions, + 'topics.bookmark_count': :post_actions, + 'topics.vote_count': :post_actions, + 'topics.off_topic_count': :post_actions, + 'topics.notify_moderators_count': :post_actions, + 'topics.spam_count': :post_actions, + 'topics.illegal_count': :post_actions, + 'topics.inappropriate_count': :post_actions, + 'topics.notify_user_count': :post_actions, - :'categories.topic_count' => :topics, - :'categories.post_count' => :posts, - :'categories.latest_post_id' => :posts, - :'categories.latest_topic_id' => :topics, - :'categories.description' => :posts, - :'categories.read_restricted' => :category_groups, - :'categories.topics_year' => :topics, - :'categories.topics_month' => :topics, - :'categories.topics_week' => :topics, - :'categories.topics_day' => :topics, - :'categories.posts_year' => :posts, - :'categories.posts_month' => :posts, - :'categories.posts_week' => :posts, - :'categories.posts_day' => :posts, + 'categories.topic_count': :topics, + 'categories.post_count': :posts, + 'categories.latest_post_id': :posts, + 'categories.latest_topic_id': :topics, + 'categories.description': :posts, + 'categories.read_restricted': :category_groups, + 'categories.topics_year': :topics, + 'categories.topics_month': :topics, + 'categories.topics_week': :topics, + 'categories.topics_day': :topics, + 'categories.posts_year': :posts, + 'categories.posts_month': :posts, + 'categories.posts_week': :posts, + 'categories.posts_day': :posts, - :'badges.grant_count' => :user_badges, - :'groups.user_count' => :group_users, + 'badges.grant_count': :user_badges, + 'groups.user_count': :group_users, - :'directory_items.likes_received' => :post_actions, - :'directory_items.likes_given' => :post_actions, - :'directory_items.topics_entered' => :user_stats, - :'directory_items.days_visited' => :user_stats, - :'directory_items.posts_read' => :user_stats, - :'directory_items.topic_count' => :topics, - :'directory_items.post_count' => :posts, + 'directory_items.likes_received': :post_actions, + 'directory_items.likes_given': :post_actions, + 'directory_items.topics_entered': :user_stats, + 'directory_items.days_visited': :user_stats, + 'directory_items.posts_read': :user_stats, + 'directory_items.topic_count': :topics, + 'directory_items.post_count': :posts, - :'post_search_data.search_data' => :posts, + 'post_search_data.search_data': :posts, - :'top_topics.yearly_posts_count' => :posts, - :'top_topics.monthly_posts_count' => :posts, - :'top_topics.weekly_posts_count' => :posts, - :'top_topics.daily_posts_count' => :posts, - :'top_topics.yearly_views_count' => :topic_views, - :'top_topics.monthly_views_count' => :topic_views, - :'top_topics.weekly_views_count' => :topic_views, - :'top_topics.daily_views_count' => :topic_views, - :'top_topics.yearly_likes_count' => :post_actions, - :'top_topics.monthly_likes_count' => :post_actions, - :'top_topics.weekly_likes_count' => :post_actions, - :'top_topics.daily_likes_count' => :post_actions, - :'top_topics.yearly_op_likes_count' => :post_actions, - :'top_topics.monthly_op_likes_count' => :post_actions, - :'top_topics.weekly_op_likes_count' => :post_actions, - :'top_topics.daily_op_likes_count' => :post_actions, - :'top_topics.all_score' => :posts, - :'top_topics.yearly_score' => :posts, - :'top_topics.monthly_score' => :posts, - :'top_topics.weekly_score' => :posts, - :'top_topics.daily_score' => :posts, + 'top_topics.yearly_posts_count': :posts, + 'top_topics.monthly_posts_count': :posts, + 'top_topics.weekly_posts_count': :posts, + 'top_topics.daily_posts_count': :posts, + 'top_topics.yearly_views_count': :topic_views, + 'top_topics.monthly_views_count': :topic_views, + 'top_topics.weekly_views_count': :topic_views, + 'top_topics.daily_views_count': :topic_views, + 'top_topics.yearly_likes_count': :post_actions, + 'top_topics.monthly_likes_count': :post_actions, + 'top_topics.weekly_likes_count': :post_actions, + 'top_topics.daily_likes_count': :post_actions, + 'top_topics.yearly_op_likes_count': :post_actions, + 'top_topics.monthly_op_likes_count': :post_actions, + 'top_topics.weekly_op_likes_count': :post_actions, + 'top_topics.daily_op_likes_count': :post_actions, + 'top_topics.all_score': :posts, + 'top_topics.yearly_score': :posts, + 'top_topics.monthly_score': :posts, + 'top_topics.weekly_score': :posts, + 'top_topics.daily_score': :posts, - :'topic_links.clicks' => :topic_link_clicks, - :'topic_search_data.search_data' => :topics, + 'topic_links.clicks': :topic_link_clicks, + 'topic_search_data.search_data': :topics, - :'topic_users.liked' => :post_actions, - :'topic_users.bookmarked' => :post_actions, + 'topic_users.liked': :post_actions, + 'topic_users.bookmarked': :post_actions, - :'user_stats.posts_read_count' => :post_timings, - :'user_stats.topic_reply_count' => :posts, - :'user_stats.first_post_created_at' => :posts, - :'user_stats.post_count' => :posts, - :'user_stats.topic_count' => :topics, - :'user_stats.likes_given' => :post_actions, - :'user_stats.likes_received' => :post_actions, + 'user_stats.posts_read_count': :post_timings, + 'user_stats.topic_reply_count': :posts, + 'user_stats.first_post_created_at': :posts, + 'user_stats.post_count': :posts, + 'user_stats.topic_count': :topics, + 'user_stats.likes_given': :post_actions, + 'user_stats.likes_received': :post_actions, - :'user_search_data.search_data' => :user_profiles, + 'user_search_data.search_data': :user_profiles, - :'users.last_posted_at' => :posts, - :'users.previous_visit_at' => :user_visits, + 'users.last_posted_at': :posts, + 'users.previous_visit_at': :user_visits, }.with_indifferent_access end end @@ -636,7 +636,7 @@ SQL } end - def self.find(id, opts={}) + def self.find(id, opts = {}) hash = DataExplorer.pstore_get("q:#{id}") unless hash return DataExplorer::Query.new if opts[:ignore_deleted] @@ -743,7 +743,7 @@ SQL return nil end - def invalid_format(string, msg=nil) + def invalid_format(string, msg = nil) if msg raise DataExplorer::ValidationError.new("'#{string}' is an invalid #{type} - #{msg}") else @@ -754,121 +754,122 @@ SQL value = nil case @type - when :int - invalid_format string, 'Not an integer' unless string =~ /^-?\d+$/ - value = string.to_i - invalid_format string, 'Too large' unless Fixnum === value - when :bigint - invalid_format string, 'Not an integer' unless string =~ /^-?\d+$/ - value = string.to_i - when :boolean - value = !!(string =~ /t|true|y|yes|1/i) - when :string - value = string - when :time - begin - value = Time.parse string - rescue ArgumentError => e - invalid_format string, e.message - end - when :date - begin - value = Date.parse string - rescue ArgumentError => e - invalid_format string, e.message - end - when :datetime - begin - value = DateTime.parse string - rescue ArgumentError => e - invalid_format string, e.message - end - when :double - if string =~ /-?\d*(\.\d+)/ - value = Float(string) - elsif string =~ /^(-?)Inf(inity)?$/i - if $1 - value = -Float::INFINITY - else - value = Float::INFINITY - end - elsif string =~ /^(-?)NaN$/i - if $1 - value = -Float::NAN - else - value = Float::NAN - end + when :int + invalid_format string, 'Not an integer' unless string =~ /^-?\d+$/ + value = string.to_i + invalid_format string, 'Too large' unless Fixnum === value + when :bigint + invalid_format string, 'Not an integer' unless string =~ /^-?\d+$/ + value = string.to_i + when :boolean + value = !!(string =~ /t|true|y|yes|1/i) + when :string + value = string + when :time + begin + value = Time.parse string + rescue ArgumentError => e + invalid_format string, e.message + end + when :date + begin + value = Date.parse string + rescue ArgumentError => e + invalid_format string, e.message + end + when :datetime + begin + value = DateTime.parse string + rescue ArgumentError => e + invalid_format string, e.message + end + when :double + if string =~ /-?\d*(\.\d+)/ + value = Float(string) + elsif string =~ /^(-?)Inf(inity)?$/i + if $1 + value = -Float::INFINITY else - invalid_format string + value = Float::INFINITY end - when :category_id - if string =~ /(.*)\/(.*)/ - parent_name = $1 - child_name = $2 - parent = Category.query_parent_category(parent_name) - invalid_format string, "Could not find category named #{parent_name}" unless parent - object = Category.query_category(child_name, parent) - invalid_format string, "Could not find subcategory of #{parent_name} named #{child_name}" unless object + elsif string =~ /^(-?)NaN$/i + if $1 + value = -Float::NAN else - object = Category.where(id: string.to_i).first || Category.where(slug: string).first || Category.where(name: string).first - invalid_format string, "Could not find category named #{string}" unless object + value = Float::NAN end - value = object.id - when :user_id, :post_id, :topic_id, :group_id, :badge_id - if string.gsub(/[ _]/, '') =~ /^-?\d+$/ - clazz_name = (/^(.*)_id$/.match(type.to_s)[1].classify.to_sym) - begin - object = Object.const_get(clazz_name).with_deleted.find(string.gsub(/[ _]/, '').to_i) - value = object.id - rescue ActiveRecord::RecordNotFound - invalid_format string, "The specified #{clazz_name} was not found" - end - elsif type == :user_id - begin - object = User.find_by_username_or_email(string) - value = object.id - rescue ActiveRecord::RecordNotFound - invalid_format string, "The user named #{string} was not found" - end - elsif type == :post_id - if string =~ /(\d+)\/(\d+)(\?u=.*)?$/ - object = Post.with_deleted.find_by(topic_id: $1, post_number: $2) - invalid_format string, "The post at topic:#{$1} post_number:#{$2} was not found" unless object - value = object.id - end - elsif type == :topic_id - if string =~ /\/t\/[^\/]+\/(\d+)/ - begin - object = Topic.with_deleted.find($1) - value = object.id - rescue ActiveRecord::RecordNotFound - invalid_format string, "The topic with id #{$1} was not found" - end - end - elsif type == :group_id - object = Group.where(name: string).first - invalid_format string, "The group named #{string} was not found" unless object - value = object.id - else - invalid_format string - end - when :int_list - value = string.split(',').map {|s| s.downcase == '#null' ? nil : s.to_i } - invalid_format string, "can't be empty" if value.length == 0 - when :string_list - value = string.split(',').map {|s| s.downcase == '#null' ? nil : s } - invalid_format string, "can't be empty" if value.length == 0 - when :user_list - value = string.split(',').map {|s| User.find_by_username_or_email(s) } - invalid_format string, "can't be empty" if value.length == 0 else - raise TypeError.new('unknown parameter type??? should not get here') + invalid_format string + end + when :category_id + if string =~ /(.*)\/(.*)/ + parent_name = $1 + child_name = $2 + parent = Category.query_parent_category(parent_name) + invalid_format string, "Could not find category named #{parent_name}" unless parent + object = Category.query_category(child_name, parent) + invalid_format string, "Could not find subcategory of #{parent_name} named #{child_name}" unless object + else + object = Category.where(id: string.to_i).first || Category.where(slug: string).first || Category.where(name: string).first + invalid_format string, "Could not find category named #{string}" unless object + end + + value = object.id + when :user_id, :post_id, :topic_id, :group_id, :badge_id + if string.gsub(/[ _]/, '') =~ /^-?\d+$/ + clazz_name = (/^(.*)_id$/.match(type.to_s)[1].classify.to_sym) + begin + object = Object.const_get(clazz_name).with_deleted.find(string.gsub(/[ _]/, '').to_i) + value = object.id + rescue ActiveRecord::RecordNotFound + invalid_format string, "The specified #{clazz_name} was not found" + end + elsif type == :user_id + begin + object = User.find_by_username_or_email(string) + value = object.id + rescue ActiveRecord::RecordNotFound + invalid_format string, "The user named #{string} was not found" + end + elsif type == :post_id + if string =~ /(\d+)\/(\d+)(\?u=.*)?$/ + object = Post.with_deleted.find_by(topic_id: $1, post_number: $2) + invalid_format string, "The post at topic:#{$1} post_number:#{$2} was not found" unless object + value = object.id + end + elsif type == :topic_id + if string =~ /\/t\/[^\/]+\/(\d+)/ + begin + object = Topic.with_deleted.find($1) + value = object.id + rescue ActiveRecord::RecordNotFound + invalid_format string, "The topic with id #{$1} was not found" + end + end + elsif type == :group_id + object = Group.where(name: string).first + invalid_format string, "The group named #{string} was not found" unless object + value = object.id + else + invalid_format string + end + when :int_list + value = string.split(',').map { |s| s.downcase == '#null' ? nil : s.to_i } + invalid_format string, "can't be empty" if value.length == 0 + when :string_list + value = string.split(',').map { |s| s.downcase == '#null' ? nil : s } + invalid_format string, "can't be empty" if value.length == 0 + when :user_list + value = string.split(',').map { |s| User.find_by_username_or_email(s) } + invalid_format string, "can't be empty" if value.length == 0 + else + raise TypeError.new('unknown parameter type??? should not get here') end value end - def self.create_from_sql(sql, opts={}) + def self.create_from_sql(sql, opts = {}) in_params = false ret_params = [] sql.split("\n").find do |line| @@ -881,7 +882,7 @@ SQL default = $3 nullable = false if type =~ /^(null)?(.*?)(null)?$/i - if $1 or $3 + if $1 || $3 nullable = true end type = $2 @@ -984,7 +985,7 @@ SQL query = DataExplorer::Query.find(params[:id].to_i) query.destroy - render json: {success: true, errors: []} + render json: { success: true, errors: [] } end def schema diff --git a/spec/controllers/queries_controller_spec.rb b/spec/controllers/queries_controller_spec.rb index dcaf453..39fc165 100644 --- a/spec/controllers/queries_controller_spec.rb +++ b/spec/controllers/queries_controller_spec.rb @@ -11,9 +11,9 @@ describe DataExplorer::QueryController do SiteSetting.data_explorer_enabled = true end - let!(:admin) {log_in_user(Fabricate(:admin))} + let!(:admin) { log_in_user(Fabricate(:admin)) } - def make_query(sql='SELECT 1 as value') + def make_query(sql = 'SELECT 1 as value') q = DataExplorer::Query.new q.id = Fabrication::Sequencer.sequence("query-id", 1) q.name = "Query number #{q.id}" @@ -74,11 +74,11 @@ describe DataExplorer::QueryController do end describe "#run" do - let!(:admin) {log_in(:admin)} + let!(:admin) { log_in(:admin) } - def run_query(id, params={}) + def run_query(id, params = {}) params = Hash[params.map { |a| [a[0], a[1].to_s] }] - xhr :post, :run, {id: id, _params: MultiJson.dump(params)} + xhr :post, :run, id: id, _params: MultiJson.dump(params) end it "can run queries" do q = make_query('SELECT 23 as my_value') @@ -96,7 +96,7 @@ describe DataExplorer::QueryController do -- int :foo = 34 SELECT :foo as my_value SQL - run_query q.id, {foo: 23} + run_query q.id, foo: 23 expect(response).to be_success expect(response_json['errors']).to eq([]) expect(response_json['success']).to eq(true) @@ -111,7 +111,7 @@ SQL expect(response_json['rows']).to eq([['34']]) # 2.3 is not an integer - run_query q.id, {foo: '2.3'} + run_query q.id, foo: '2.3' expect(response).to_not be_success expect(response_json['errors']).to_not eq([]) expect(response_json['success']).to eq(false)