diff --git a/Gemfile.lock b/Gemfile.lock index 1f0490eff79..248845f02b6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -43,8 +43,8 @@ GEM rake (>= 10.4, < 13.0) arel (9.0.0) ast (2.4.0) - aws-eventstream (1.0.0) - aws-partitions (1.91.0) + aws-eventstream (1.0.1) + aws-partitions (1.92.0) aws-sdk-core (3.21.2) aws-eventstream (~> 1.0) aws-partitions (~> 1.0) @@ -53,7 +53,7 @@ GEM aws-sdk-kms (1.5.0) aws-sdk-core (~> 3) aws-sigv4 (~> 1.0) - aws-sdk-s3 (1.13.0) + aws-sdk-s3 (1.14.0) aws-sdk-core (~> 3, >= 3.21.2) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.0) @@ -108,7 +108,7 @@ GEM erubi (1.7.1) excon (0.62.0) execjs (2.7.0) - exifr (1.2.5) + exifr (1.3.4) fabrication (2.20.1) fakeweb (1.3.0) faraday (0.12.2) @@ -130,7 +130,7 @@ GEM guess_html_encoding (0.0.11) hashdiff (0.3.7) hashie (3.5.7) - highline (1.7.10) + highline (2.0.0) hiredis (0.6.1) hkdf (0.3.0) htmlentities (4.3.4) @@ -176,7 +176,7 @@ GEM mini_portile2 (2.3.0) mini_racer (0.1.15) libv8 (~> 6.3) - mini_sql (0.1.5) + mini_sql (0.1.9) mini_suffix (0.3.0) ffi (~> 1.9) minitest (5.11.3) @@ -261,7 +261,7 @@ GEM rack-openid (1.3.1) rack (>= 1.1.0) ruby-openid (>= 2.1.8) - rack-protection (2.0.2) + rack-protection (2.0.3) rack rack-test (1.0.0) rack (>= 1.0, < 3) diff --git a/app/models/category_user.rb b/app/models/category_user.rb index 0ae88ecd423..321089335eb 100644 --- a/app/models/category_user.rb +++ b/app/models/category_user.rb @@ -64,13 +64,13 @@ class CategoryUser < ActiveRecord::Base def self.auto_track(opts = {}) - builder = SqlBuilder.new <= :start_date", start_date: opts[:start_date]) if opts[:start_date] builder.where("t.created_at < :end_date", end_date: opts[:end_date]) if opts[:end_date] builder.where("t.category_id = :category_id", category_id: opts[:category_id]) if opts[:category_id] @@ -1253,7 +1253,7 @@ class Topic < ActiveRecord::Base builder.where("p.user_id in (:user_ids)", user_ids: opts[:user_ids]) if opts[:user_ids] builder.where("p.post_type = :post_type", post_type: Post.types[:regular]) builder.where("EXTRACT(EPOCH FROM p.created_at - t.created_at) > 0") - builder.exec + builder.query_hash end def self.time_to_first_response_per_day(start_date, end_date, opts = {}) @@ -1280,13 +1280,13 @@ class Topic < ActiveRecord::Base SQL def self.with_no_response_per_day(start_date, end_date, category_id = nil) - builder = SqlBuilder.new(WITH_NO_RESPONSE_SQL) + builder = DB.build(WITH_NO_RESPONSE_SQL) builder.where("t.created_at >= :start_date", start_date: start_date) if start_date builder.where("t.created_at < :end_date", end_date: end_date) if end_date builder.where("t.category_id = :category_id", category_id: category_id) if category_id builder.where("t.archetype <> '#{Archetype.private_message}'") builder.where("t.deleted_at IS NULL") - builder.exec + builder.query_hash end WITH_NO_RESPONSE_TOTAL_SQL ||= <<-SQL @@ -1302,11 +1302,11 @@ class Topic < ActiveRecord::Base SQL def self.with_no_response_total(opts = {}) - builder = SqlBuilder.new(WITH_NO_RESPONSE_TOTAL_SQL) + builder = DB.build(WITH_NO_RESPONSE_TOTAL_SQL) builder.where("t.category_id = :category_id", category_id: opts[:category_id]) if opts[:category_id] builder.where("t.archetype <> '#{Archetype.private_message}'") builder.where("t.deleted_at IS NULL") - builder.exec.first["count"].to_i + builder.query_single.first.to_i end def convert_to_public_topic(user) diff --git a/app/models/topic_tracking_state.rb b/app/models/topic_tracking_state.rb index 61b3fab8710..fe71d76bad2 100644 --- a/app/models/topic_tracking_state.rb +++ b/app/models/topic_tracking_state.rb @@ -174,8 +174,12 @@ class TopicTrackingState sql << "\nUNION ALL\n\n" sql << report_raw_sql(topic_id: topic_id, skip_new: true, skip_order: true, staff: user.staff?) - SqlBuilder.new(sql) - .map_exec(TopicTrackingState, user_id: user.id, topic_id: topic_id, min_new_topic_date: Time.at(SiteSetting.min_new_topics_time).to_datetime) + DB.query( + sql, + user_id: user.id, + topic_id: topic_id, + min_new_topic_date: Time.at(SiteSetting.min_new_topics_time).to_datetime + ) end def self.report_raw_sql(opts = nil) diff --git a/app/models/topic_user.rb b/app/models/topic_user.rb index b41fabb3daa..9cbf1b6383b 100644 --- a/app/models/topic_user.rb +++ b/app/models/topic_user.rb @@ -370,28 +370,28 @@ class TopicUser < ActiveRecord::Base return end - builder = SqlBuilder.new < LEAST(GREATEST(last_read, last_read_post_number), max_post_number) OR - highest_seen_post_number <> LEAST(max_post_number,GREATEST(t.highest_seen_post_number, last_read)) -) -SQL + builder.where <<~SQL + X.topic_id = t.topic_id AND + X.user_id = t.user_id AND + ( + last_read_post_number <> LEAST(GREATEST(last_read, last_read_post_number), max_post_number) OR + highest_seen_post_number <> LEAST(max_post_number,GREATEST(t.highest_seen_post_number, last_read)) + ) + SQL if topic_id builder.where("t.topic_id = :topic_id", topic_id: topic_id) diff --git a/app/models/topic_view_item.rb b/app/models/topic_view_item.rb index 3549825dec8..9fbb9aa98a0 100644 --- a/app/models/topic_view_item.rb +++ b/app/models/topic_view_item.rb @@ -28,7 +28,7 @@ class TopicViewItem < ActiveRecord::Base /*where*/ )" - builder = SqlBuilder.new(sql) + builder = DB.build(sql) if !user_id builder.where("ip_address = :ip_address AND topic_id = :topic_id AND user_id IS NULL") @@ -41,7 +41,7 @@ class TopicViewItem < ActiveRecord::Base Topic.where(id: topic_id).update_all 'views = views + 1' - if result.cmd_tuples > 0 + if result > 0 UserStat.where(user_id: user_id).update_all 'topics_entered = topics_entered + 1' if user_id end diff --git a/app/models/user_action.rb b/app/models/user_action.rb index 981cb4a9c44..325300389a7 100644 --- a/app/models/user_action.rb +++ b/app/models/user_action.rb @@ -39,16 +39,6 @@ class UserAction < ActiveRecord::Base ASSIGNED, ].each_with_index.to_a.flatten] - # note, this is temporary until we upgrade to rails 4 - # in rails 4 types are mapped correctly so you dont end up - # having strings where you would expect bools - class UserActionRow < OpenStruct - include ActiveModel::SerializerSupport - - def as_json(options = nil) - @table.as_json(options) - end - end def self.last_action_in_topic(user_id, topic_id) UserAction.where(user_id: user_id, @@ -59,25 +49,24 @@ class UserAction < ActiveRecord::Base def self.stats(user_id, guardian) # Sam: I tried this in AR and it got complex - builder = UserAction.sql_builder < ORDER[b.action_type] } - results end @@ -139,19 +128,50 @@ SQL stream(action_id: action_id, guardian: guardian).first end + NULL_QUEUED_STREAM_COLS = %i{ + cooked + uploaded_avatar_id + acting_name + acting_username + acting_user_id + target_name + target_username + target_user_id + post_number + post_id + deleted + hidden + post_type + action_type + action_code + action_code_who + topic_closed + topic_id + topic_archived + }.map! { |s| "NULL as #{s}" }.join(", ") + def self.stream_queued(opts = nil) opts ||= {} offset = opts[:offset] || 0 limit = opts[:limit] || 60 - builder = SqlBuilder.new <<-SQL + # this is somewhat ugly, but the serializer wants all these columns + # it is more correct to have an object with all the fields needed + # cause then we can catch and change if we ever add columns + builder = DB.build <<~SQL SELECT a.id, - t.title, a.action_type, a.created_at, t.id topic_id, - u.username, u.name, u.id AS user_id, + t.title, + a.action_type, + a.created_at, + t.id topic_id, + u.username, + u.name, + u.id AS user_id, qp.raw, - t.category_id + t.category_id, + #{NULL_QUEUED_STREAM_COLS} FROM user_actions as a JOIN queued_posts AS qp ON qp.id = a.queued_post_id LEFT OUTER JOIN topics t on t.id = qp.topic_id @@ -169,7 +189,7 @@ SQL .order_by("a.created_at desc") .offset(offset.to_i) .limit(limit.to_i) - .map_exec(UserActionRow) + .query end def self.stream(opts = nil) @@ -197,7 +217,7 @@ SQL # The weird thing is that target_post_id can be null, so it makes everything # ever so more complex. Should we allow this, not sure. - builder = SqlBuilder.new <<-SQL + builder = DB.build <<~SQL SELECT a.id, t.title, a.action_type, a.created_at, t.id topic_id, @@ -249,7 +269,7 @@ SQL .limit(limit.to_i) end - builder.map_exec(UserActionRow) + builder.query end def self.log_action!(hash) @@ -321,19 +341,19 @@ SQL def self.synchronize_target_topic_ids(post_ids = nil) # nuke all dupes, using magic - builder = SqlBuilder.new < 0 AND - user_actions.id > ua2.id -SQL + builder.where <<~SQL + user_actions.action_type = ua2.action_type AND + user_actions.user_id = ua2.user_id AND + user_actions.acting_user_id = ua2.acting_user_id AND + user_actions.target_post_id = ua2.target_post_id AND + user_actions.target_post_id > 0 AND + user_actions.id > ua2.id + SQL if post_ids builder.where("user_actions.target_post_id in (:post_ids)", post_ids: post_ids) @@ -341,9 +361,11 @@ SQL builder.exec - builder = SqlBuilder.new("UPDATE user_actions - SET target_topic_id = (select topic_id from posts where posts.id = target_post_id) - /*where*/") + builder = DB.build <<~SQL + UPDATE user_actions + SET target_topic_id = (select topic_id from posts where posts.id = target_post_id) + /*where*/ + SQL builder.where("target_topic_id <> (select topic_id from posts where posts.id = target_post_id)") if post_ids diff --git a/app/models/user_profile_view.rb b/app/models/user_profile_view.rb index 237318a101c..6864b571793 100644 --- a/app/models/user_profile_view.rb +++ b/app/models/user_profile_view.rb @@ -25,7 +25,7 @@ class UserProfileView < ActiveRecord::Base /*where*/ )" - builder = SqlBuilder.new(sql) + builder = DB.build(sql) if !user_id builder.where("viewed_at = :viewed_at AND ip_address = :ip_address AND user_profile_id = :user_profile_id AND user_id IS NULL") @@ -35,7 +35,7 @@ class UserProfileView < ActiveRecord::Base result = builder.exec(user_profile_id: user_profile_id, ip_address: ip, viewed_at: at, user_id: user_id) - if result.cmd_tuples > 0 + if result > 0 UserProfile.find(user_profile_id).increment!(:views) end end diff --git a/app/models/user_search.rb b/app/models/user_search.rb index a9eceda1e9a..3acdf917c3e 100644 --- a/app/models/user_search.rb +++ b/app/models/user_search.rb @@ -54,7 +54,7 @@ class UserSearch users = users.includes(:user_search_data) .references(:user_search_data) .where("user_search_data.search_data @@ #{query}") - .order(User.sql_fragment("CASE WHEN username_lower LIKE ? THEN 0 ELSE 1 END ASC", @term_like)) + .order(DB.sql_fragment("CASE WHEN username_lower LIKE ? THEN 0 ELSE 1 END ASC", @term_like)) else users = users.where("username_lower LIKE :term_like", term_like: @term_like) diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index 8446b5bcda7..6999be26e1a 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -184,7 +184,7 @@ class BadgeGranter # hack to allow for params, otherwise sanitizer will trigger sprintf count_sql = "SELECT COUNT(*) count FROM (#{sql}) q WHERE :backfill = :backfill" - grant_count = SqlBuilder.map_exec(OpenStruct, count_sql, params).first.count.to_i + grant_count = DB.query_single(count_sql, params).first.to_i grants_sql = if opts[:target_posts] diff --git a/app/services/user_merger.rb b/app/services/user_merger.rb index 4fc678b13f8..1d31a802e7c 100644 --- a/app/services/user_merger.rb +++ b/app/services/user_merger.rb @@ -386,7 +386,7 @@ class UserMerger conditions = Array.wrap(opts[:conditions]) updates = Array.wrap(opts[:updates]) - builder = SqlBuilder.new(<<~SQL) + builder = DB.build(<<~SQL) UPDATE #{table_name} AS x /*set*/ WHERE x.#{user_id_column_name} = :source_user_id AND NOT EXISTS( diff --git a/db/migrate/20141014191645_fix_tos_name.rb b/db/migrate/20141014191645_fix_tos_name.rb index 42daa0a1508..16976a944dd 100644 --- a/db/migrate/20141014191645_fix_tos_name.rb +++ b/db/migrate/20141014191645_fix_tos_name.rb @@ -1,7 +1,7 @@ class FixTosName < ActiveRecord::Migration[4.2] def up I18n.overrides_disabled do - execute ActiveRecord::Base.sql_fragment('UPDATE user_fields SET name = ? WHERE name = ?', I18n.t('terms_of_service.title'), I18n.t("terms_of_service.signup_form_message")) + execute DB.sql_fragment('UPDATE user_fields SET name = ? WHERE name = ?', I18n.t('terms_of_service.title'), I18n.t("terms_of_service.signup_form_message")) end end diff --git a/db/migrate/20170313192741_add_themes.rb b/db/migrate/20170313192741_add_themes.rb index be8fa82e044..374d4abe2e2 100644 --- a/db/migrate/20170313192741_add_themes.rb +++ b/db/migrate/20170313192741_add_themes.rb @@ -40,7 +40,7 @@ class AddThemes < ActiveRecord::Migration[4.2] RETURNING * SQL - sql = ActiveRecord::Base.sql_fragment(sql, now: Time.zone.now, key: theme_key) + sql = DB.sql_fragment(sql, now: Time.zone.now, key: theme_key) theme_id = execute(sql).to_a[0]["id"].to_i end @@ -62,7 +62,7 @@ SQL INSERT INTO site_settings(name, data_type, value, created_at, updated_at) VALUES('default_theme_key', 1, :key, :now, :now) SQL - sql = ActiveRecord::Base.sql_fragment(sql, now: Time.zone.now, key: theme_key) + sql = DB.sql_fragment(sql, now: Time.zone.now, key: theme_key) execute(sql) end diff --git a/lib/flag_query.rb b/lib/flag_query.rb index e963269a4f3..43b3206ddf3 100644 --- a/lib/flag_query.rb +++ b/lib/flag_query.rb @@ -32,9 +32,9 @@ module FlagQuery post_ids = post_ids_relation.pluck(:post_id).uniq - posts = SqlBuilder.new(" + posts = DB.query(<<~SQL, post_ids: post_ids) SELECT p.id, - p.cooked, + p.cooked as excerpt, p.raw, p.user_id, p.topic_id, @@ -43,10 +43,13 @@ module FlagQuery p.hidden, p.deleted_at, p.user_deleted, + NULL as post_actions, + NULL as post_action_ids, (SELECT created_at FROM post_revisions WHERE post_id = p.id AND user_id = p.user_id ORDER BY created_at DESC LIMIT 1) AS last_revised_at, (SELECT COUNT(*) FROM post_actions WHERE (disagreed_at IS NOT NULL OR agreed_at IS NOT NULL OR deferred_at IS NOT NULL) AND post_id = p.id)::int AS previous_flags_count FROM posts p - WHERE p.id in (:post_ids)").map_exec(OpenStruct, post_ids: post_ids) + WHERE p.id in (:post_ids) + SQL post_lookup = {} user_ids = Set.new @@ -55,8 +58,7 @@ module FlagQuery posts.each do |p| user_ids << p.user_id topic_ids << p.topic_id - p.excerpt = Post.excerpt(p.cooked) - p.delete_field(:cooked) + p.excerpt = Post.excerpt(p.excerpt) post_lookup[p.id] = p end @@ -127,7 +129,7 @@ module FlagQuery # maintain order posts = post_ids.map { |id| post_lookup[id] } # TODO: add serializer so we can skip this - posts.map!(&:marshal_dump) + posts.map!(&:to_h) users = User.includes(:user_stat).where(id: user_ids.to_a).to_a User.preload_custom_fields(users, User.whitelisted_user_custom_fields(guardian)) diff --git a/lib/migration/column_dropper.rb b/lib/migration/column_dropper.rb index a594105622b..5d9e508e808 100644 --- a/lib/migration/column_dropper.rb +++ b/lib/migration/column_dropper.rb @@ -32,21 +32,22 @@ module Migration end def droppable? - builder = SqlBuilder.new(<<~SQL) + builder = DB.build(<<~SQL) SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS /*where*/ LIMIT 1 SQL - builder.where("table_schema = 'public'") + builder + .where("table_schema = 'public'") .where("table_name = :table") .where("column_name IN (:columns)") .where(previous_migration_done) .exec(table: @table, columns: @columns, delay: "#{@delay} seconds", - after_migration: @after_migration).to_a.length > 0 + after_migration: @after_migration) > 0 end def execute_drop! diff --git a/lib/mini_sql_multisite_connection.rb b/lib/mini_sql_multisite_connection.rb index 5af8ed2d2e7..c6842fe19ab 100644 --- a/lib/mini_sql_multisite_connection.rb +++ b/lib/mini_sql_multisite_connection.rb @@ -36,4 +36,13 @@ class MiniSqlMultisiteConnection < MiniSql::Connection def build(sql) CustomBuilder.new(self, sql) end + + def sql_fragment(query, *args) + if args.length > 0 + param_encoder.encode(query, *args) + else + query + end + end + end diff --git a/lib/score_calculator.rb b/lib/score_calculator.rb index baf93cb457e..41272243ddd 100644 --- a/lib/score_calculator.rb +++ b/lib/score_calculator.rb @@ -32,7 +32,7 @@ class ScoreCalculator @weightings.each_key { |k| components << "COALESCE(posts.#{k}, 0) * :#{k}" } components = components.join(" + ") - builder = SqlBuilder.new < posts.percent_rank") filter_topics(builder, opts) - while builder.exec.cmd_tuples == limit + while builder.exec == limit end end def update_topics_rank(opts) - builder = SqlBuilder.new("UPDATE topics AS topics - SET has_summary = (topics.like_count >= :likes_required AND - topics.posts_count >= :posts_required AND - x.max_score >= :score_required), - score = x.avg_score - FROM (SELECT p.topic_id, - MAX(p.score) AS max_score, - AVG(p.score) AS avg_score - FROM posts AS p - GROUP BY p.topic_id) AS x - /*where*/") + builder = DB.build <<~SQL + UPDATE topics AS topics + SET has_summary = (topics.like_count >= :likes_required AND + topics.posts_count >= :posts_required AND + x.max_score >= :score_required), + score = x.avg_score + FROM (SELECT p.topic_id, + MAX(p.score) AS max_score, + AVG(p.score) AS avg_score + FROM posts AS p + GROUP BY p.topic_id) AS x + /*where*/ + SQL - builder.where("x.topic_id = topics.id AND - ( - (topics.score <> x.avg_score OR topics.score IS NULL) OR - (topics.has_summary IS NULL OR topics.has_summary <> ( - topics.like_count >= :likes_required AND - topics.posts_count >= :posts_required AND - x.max_score >= :score_required - )) - ) - ", - likes_required: SiteSetting.summary_likes_required, - posts_required: SiteSetting.summary_posts_required, - score_required: SiteSetting.summary_score_threshold) + defaults = { + likes_required: SiteSetting.summary_likes_required, + posts_required: SiteSetting.summary_posts_required, + score_required: SiteSetting.summary_score_threshold + } + + builder.where(<<~SQL, defaults) + x.topic_id = topics.id AND + ( + (topics.score <> x.avg_score OR topics.score IS NULL) OR + (topics.has_summary IS NULL OR topics.has_summary <> ( + topics.like_count >= :likes_required AND + topics.posts_count >= :posts_required AND + x.max_score >= :score_required + )) + ) + SQL filter_topics(builder, opts) @@ -116,11 +122,13 @@ SQL def update_topics_percent_rank(opts) - builder = SqlBuilder.new("UPDATE topics SET percent_rank = x.percent_rank - FROM (SELECT id, percent_rank() - OVER (ORDER BY SCORE DESC) as percent_rank - FROM topics) AS x - /*where*/") + builder = DB.build <<~SQL + UPDATE topics SET percent_rank = x.percent_rank + FROM (SELECT id, percent_rank() + OVER (ORDER BY SCORE DESC) as percent_rank + FROM topics) AS x + /*where*/ + SQL builder.where("x.id = topics.id AND (topics.percent_rank <> x.percent_rank OR topics.percent_rank IS NULL)") diff --git a/lib/site_settings/db_provider.rb b/lib/site_settings/db_provider.rb index 0887e0edc4d..9300be2dba1 100644 --- a/lib/site_settings/db_provider.rb +++ b/lib/site_settings/db_provider.rb @@ -14,15 +14,14 @@ class SiteSettings::DbProvider return [] unless table_exists? # Not leaking out AR records, cause I want all editing to happen via this API - SqlBuilder.new("SELECT name, data_type, value FROM #{@model.table_name}").map_exec(OpenStruct) + DB.query("SELECT name, data_type, value FROM #{@model.table_name}") end def find(name) return nil unless table_exists? # Not leaking out AR records, cause I want all editing to happen via this API - SqlBuilder.new("SELECT name, data_type, value FROM #{@model.table_name} WHERE name = :name") - .map_exec(OpenStruct, name: name) + DB.query("SELECT name, data_type, value FROM #{@model.table_name} WHERE name = ?", name) .first end diff --git a/lib/sql_builder.rb b/lib/sql_builder.rb index 3498cbe6175..f21ae4b1f87 100644 --- a/lib/sql_builder.rb +++ b/lib/sql_builder.rb @@ -1,6 +1,9 @@ class SqlBuilder def initialize(template, klass = nil) + + Discourse.deprecate("SqlBuilder is deprecated and will be removed, please use DB.build instead!") + @args = {} @sql = template @sections = {} @@ -75,12 +78,8 @@ class SqlBuilder class RailsDateTimeDecoder < PG::SimpleDecoder def decode(string, tuple = nil, field = nil) - if Rails.version >= "4.2.0" - @caster ||= ActiveRecord::Type::DateTime.new - @caster.cast(string) - else - ActiveRecord::ConnectionAdapters::Column.string_to_time string - end + @caster ||= ActiveRecord::Type::DateTime.new + @caster.cast(string) end end @@ -118,9 +117,3 @@ class SqlBuilder end end - -class ActiveRecord::Base - def self.sql_builder(template) - SqlBuilder.new(template, self) - end -end diff --git a/lib/tasks/posts.rake b/lib/tasks/posts.rake index 9909bb3c01e..cafe17bc2c6 100644 --- a/lib/tasks/posts.rake +++ b/lib/tasks/posts.rake @@ -283,7 +283,7 @@ task 'posts:reorder_posts', [:topic_id] => [:environment] do |_, args| Post.transaction do # update sort_order and flip post_number to prevent # unique constraint violations when updating post_number - builder = SqlBuilder.new(<<~SQL) + builder = DB.build(<<~SQL) WITH ordered_posts AS ( SELECT id, diff --git a/spec/components/sql_builder_spec.rb b/spec/components/sql_builder_spec.rb deleted file mode 100644 index 4ccdde49a25..00000000000 --- a/spec/components/sql_builder_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# encoding: utf-8 -require 'rails_helper' -require_dependency 'sql_builder' - -describe SqlBuilder do - - describe "attached" do - before do - @builder = Post.sql_builder("select * from posts /*where*/ /*limit*/") - end - - it "should find a post by id" do - p = Fabricate(:post) - @builder.where('id = :id and topic_id = :topic_id', id: p.id, topic_id: p.topic_id) - p2 = @builder.exec.first - expect(p2.id).to eq(p.id) - expect(p2).to eq(p) - end - end - - describe "map_exec" do - class SqlBuilder::TestClass - attr_accessor :int, :string, :date, :text, :bool - end - - it "correctly maps to a klass" do - rows = SqlBuilder.new("SELECT - 1 AS int, - 'string' AS string, - CAST(NOW() at time zone 'utc' AS timestamp without time zone) AS date, - 'text'::text AS text, - true AS bool") - .map_exec(SqlBuilder::TestClass) - - expect(rows.count).to eq(1) - row = rows[0] - expect(row.int).to eq(1) - expect(row.string).to eq("string") - expect(row.text).to eq("text") - expect(row.bool).to eq(true) - expect(row.date).to be_within(10.seconds).of(DateTime.now) - end - end - - describe "detached" do - before do - @builder = SqlBuilder.new("select * from (select :a A union all select :b) as X /*where*/ /*order_by*/ /*limit*/ /*offset*/") - end - - it "should allow for 1 param exec" do - expect(@builder.exec(a: 1, b: 2).values[0][0]).to eq(1) - end - - it "should allow for a single where" do - @builder.where(":a = 1") - expect(@builder.exec(a: 1, b: 2).values[0][0]).to eq(1) - end - - it "should allow where chaining" do - @builder.where(":a = 1") - @builder.where("2 = 1") - expect(@builder.exec(a: 1, b: 2).to_a.length).to eq(0) - end - - it "should allow order by" do - expect(@builder.order_by("A desc").limit(1) - .exec(a: 1, b: 2).values[0][0]).to eq(2) - end - it "should allow offset" do - expect(@builder.order_by("A desc").offset(1) - .exec(a: 1, b: 2).values[0][0]).to eq(1) - end - end - -end diff --git a/spec/models/user_action_spec.rb b/spec/models/user_action_spec.rb index 6ab8a1537ab..9a172ded34f 100644 --- a/spec/models/user_action_spec.rb +++ b/spec/models/user_action_spec.rb @@ -43,7 +43,7 @@ describe UserAction do end def stats_for_user(viewer = nil) - UserAction.stats(user.id, Guardian.new(viewer)).map { |r| r["action_type"].to_i }.sort + UserAction.stats(user.id, Guardian.new(viewer)).map { |r| r.action_type.to_i }.sort end def stream(viewer = nil)