require 'assert' require 'mr/read_model/subquery' require 'ardb/relation_spy' require 'mr/fake_record' require 'mr/read_model/set_querying' require 'test/support/read_model/querying' module MR::ReadModel class UnitTests < Assert::Context include Querying::TestHelpers desc "MR::ReadModel" setup do @column = column = Factory.string @subquery_block = proc do read_model do select column from FakeTestRecord end end @subquery_with_params_block = proc do read_model do select{ |params| params['column'] } from FakeTestRecord end end end end class SubqueryTests < UnitTests desc "Subquery" setup do @subquery_class = Class.new{ include MR::ReadModel::Subquery } @subquery = @subquery_class.new(&@subquery_block) end subject{ @subquery } should have_readers :read_model_class should have_imeths :read_model, :build_sql should "know its read model class" do read_model_class = subject.read_model_class assert_includes MR::ReadModel, read_model_class assert_includes MR::ReadModel::SetQuerying, read_model_class relation_spy = read_model_class.relation assert_static_expression_added relation_spy, :select, @column end should "build the subquery's SQL using `build_sql`" do exp = "(#{subject.read_model_class.relation.build_for_all.to_sql})" assert_equal exp, subject.build_sql subquery = @subquery_class.new(&@subquery_with_params_block) params = { 'column' => Factory.string } exp = "(#{subquery.read_model_class.build_sql(params)})" assert_equal exp, subquery.build_sql(params) end end class AliasSubqueryTests < UnitTests desc "AliasSubquery" setup do @subquery_class = Class.new{ include MR::ReadModel::AliasSubquery } end subject{ @subquery_class } should "be a MR subquery" do assert_includes MR::ReadModel::Subquery, subject end end class AliasSubqueryInitTests < AliasSubqueryTests desc "when init" setup do @subquery = @subquery_class.new(&@subquery_block) end subject{ @subquery } should have_imeths :alias_sql, :as, :build_sql should "know its default alias sql" do assert_equal "", subject.alias_sql end should "allow changing its alias sql using `as`" do alias_name = Factory.string subject.as(alias_name) assert_equal "AS #{alias_name}", subject.alias_sql end should "raise an argument error if passing a blank alias" do assert_raises(ArgumentError){ subject.as(nil) } assert_raises(ArgumentError){ subject.as('') } assert_raises(ArgumentError){ subject.as(' ') } end should "build the subquery's SQL using `build_sql`" do alias_name = Factory.string subject.as(alias_name) exp = "(#{subject.read_model_class.build_sql}) #{subject.alias_sql}" assert_equal exp, subject.build_sql subquery = @subquery_class.new(&@subquery_with_params_block) subquery.as(alias_name) params = { 'column' => Factory.string } exp = "(#{subquery.read_model_class.build_sql(params)}) #{subquery.alias_sql}" assert_equal exp, subquery.build_sql(params) end should "raise an invalid subquery error if an alias hasn't been set" do assert_raises(InvalidSubqueryError){ subject.build_sql } end end class FromSubqueryTests < UnitTests desc "FromSubquery" setup do @subquery_class = MR::ReadModel::FromSubquery end subject{ @subquery_class } should "be a MR alias subquery" do assert_includes MR::ReadModel::AliasSubquery, subject end end class FromSubqueryInitTests < FromSubqueryTests desc "when init" setup do @subquery = @subquery_class.new(&@subquery_block) end subject{ @subquery } should have_imeths :record_class should "know its record class" do assert_equal FakeTestRecord, subject.record_class subquery_block = @subquery_block subquery = @subquery_class.new do read_model{ from_subquery(&subquery_block) } end assert_equal FakeTestRecord, subquery.record_class end end class JoinSubqueryTests < UnitTests desc "JoinSubquery" setup do @subquery_class = MR::ReadModel::JoinSubquery end subject{ @subquery_class } should "be a MR alias subquery" do assert_includes MR::ReadModel::AliasSubquery, subject end should "know its join sql constants" do assert_equal 'JOIN', subject::DEFAULT_JOIN_SQL exp = { :inner => "INNER JOIN", :left => "LEFT OUTER JOIN", :right => "RIGHT OUTER JOIN", :full => "FULL OUTER JOIN" } assert_equal exp, subject::JOIN_SQL assert_equal subject::DEFAULT_JOIN_SQL, subject::JOIN_SQL[Factory.string] end end class JoinSubqueryInitTests < JoinSubqueryTests desc "when init" setup do @type = if Factory.boolean @subquery_class::JOIN_SQL.keys.sample else Factory.string end @subquery = @subquery_class.new(@type, &@subquery_block) end subject{ @subquery } should have_readers :join_sql should have_imeths :conditions_sql, :on, :build_sql should "know its join sql" do assert_equal @subquery_class::JOIN_SQL[@type], subject.join_sql end should "know its default conditions sql" do assert_equal "", subject.conditions_sql end should "allow changing its conditions sql using `on`" do conditions = Factory.string subject.on(conditions) assert_equal "ON #{conditions}", subject.conditions_sql end should "build the subquery's SQL using `build_sql`" do alias_name = Factory.string subject.as(alias_name) conditions = Factory.string subject.on(conditions) exp = "#{subject.join_sql} " \ "(#{subject.read_model_class.relation.build_for_all.to_sql}) " \ "#{subject.alias_sql} #{subject.conditions_sql}" assert_equal exp, subject.build_sql subquery = @subquery_class.new(@type, &@subquery_with_params_block) subquery.as(alias_name) subquery.on(conditions) params = { 'column' => Factory.string } exp = "#{subquery.join_sql} " \ "(#{subquery.read_model_class.build_sql(params)}) " \ "#{subquery.alias_sql} #{subquery.conditions_sql}" assert_equal exp, subquery.build_sql(params) end end class FakeTestRecord include MR::FakeRecord def self.scoped Ardb::RelationSpy.new end end end