1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
|
require_relative "spec_helper"
describe "Model attribute setters" do
before do
@c = Class.new(Sequel::Model(:items)) do
columns :id, :x, :y, :"x y"
end
@o = @c.new
DB.reset
end
it "refresh should return self" do
@o = @c[1]
def @o._refresh(*) [] end
@o.refresh.must_equal @o
end
it "should mark the column value as changed" do
@o.changed_columns.must_equal []
@o.x = 2
@o.changed_columns.must_equal [:x]
@o.y = 3
@o.changed_columns.must_equal [:x, :y]
@o.changed_columns.clear
@o[:x] = 2
@o.changed_columns.must_equal [:x]
@o[:y] = 3
@o.changed_columns.must_equal [:x, :y]
end
it "should handle columns that can't be called like normal ruby methods" do
@o.send(:"x y=", 3)
@o.changed_columns.must_equal [:"x y"]
@o.values.must_equal(:"x y"=>3)
@o.send(:"x y").must_equal 3
end
end
describe "Model attribute getters/setters" do
before do
a = @a = []
@c = Class.new(Sequel::Model(:items)) do
columns :id, :x, :"x y", :require_modification
[:x, :"x y"].each do |c|
define_method(c) do
a << c
super()
end
define_method(:"#{c}=") do |v|
a << :"#{c}=" << v
super(v)
end
end
end
DB.reset
end
it "should not override existing methods" do
@o = @c.new
@o.values.merge!(:x=>4, :"x y"=>5, :require_modification=>6)
@o.x.must_equal 4
@o.x = 1
@o.send(:"x y").must_equal 5
@o.send(:"x y=", 2)
@o.require_modification.must_equal true
@o.require_modification = 3
@o.values.must_equal(:x=>1, :"x y"=>2, :require_modification=>6)
@a.must_equal [:x, :x=, 1, :"x y", :"x y=", 2]
end
it "should not override existing methods in subclasses" do
@c = Class.new(@c)
@c.columns(:id, :x, :y, :"x y", :require_modification)
@o = @c.new
@o.values.merge!(:x=>4, :"x y"=>5, :require_modification=>6)
@o.x.must_equal 4
@o.x = 1
@o.send(:"x y").must_equal 5
@o.send(:"x y=", 2)
@o.require_modification.must_equal true
@o.require_modification = 3
@o.values.must_equal(:x=>1, :"x y"=>2, :require_modification=>6)
@a.must_equal [:x, :x=, 1, :"x y", :"x y=", 2]
end
end
describe "Model.def_column_alias" do
before do
@o = Class.new(Sequel::Model(:items)) do
columns :id
def_column_alias(:id2, :id)
end.load(:id=>1)
DB.reset
end
it "should create an getter alias for the column" do
@o.id2.must_equal 1
end
it "should create an setter alias for the column" do
@o.id2 = 2
@o.id2.must_equal 2
@o.values.must_equal(:id => 2)
end
end
describe Sequel::Model, "dataset" do
before do
@a = Class.new(Sequel::Model(:items))
@b = Class.new(Sequel::Model)
class ::Elephant < Sequel::Model(:ele1); end
class ::Maggot < Sequel::Model; end
class ::ShoeSize < Sequel::Model; end
class ::BootSize < ShoeSize; end
end
after do
[:Elephant, :Maggot, :ShoeSize, :BootSize].each{|x| Object.send(:remove_const, x)}
end
it "should default to the plural of the class name" do
Maggot.dataset.sql.must_equal 'SELECT * FROM maggots'
ShoeSize.dataset.sql.must_equal 'SELECT * FROM shoe_sizes'
end
it "should return the dataset for the superclass if available" do
BootSize.dataset.sql.must_equal 'SELECT * FROM shoe_sizes'
end
it "should return the correct dataset if set explicitly" do
Elephant.dataset.sql.must_equal 'SELECT * FROM ele1'
@a.dataset.sql.must_equal 'SELECT * FROM items'
end
it "should raise if no dataset is explicitly set and the class is anonymous" do
proc {@b.dataset}.must_raise(Sequel::Error)
end
it "should not override dataset explicitly set when subclassing" do
sc = Class.new(::Elephant) do
set_dataset :foo
end
sc.table_name.must_equal :foo
end
end
describe Sequel::Model, "has_dataset?" do
it "should return whether the model has a dataset" do
c = Class.new(Sequel::Model)
c.has_dataset?.must_equal false
c.dataset = c.db[:table]
c.has_dataset?.must_equal true
end
end
describe Sequel::Model, "implicit table names" do
after do
Object.send(:remove_const, :BlahBlah)
end
it "should disregard namespaces for the table name" do
module ::BlahBlah
class MwaHaHa < Sequel::Model
end
end
BlahBlah::MwaHaHa.dataset.sql.must_equal 'SELECT * FROM mwa_ha_has'
end
it "should automatically set datasets when anonymous class of Sequel::Model is used as superclass" do
class BlahBlah < Class.new(Sequel::Model); end
BlahBlah.dataset.sql.must_equal 'SELECT * FROM blah_blahs'
end
end
describe Sequel::Model, ".dataset_module" do
before do
@c = Class.new(Sequel::Model(:items))
end
it "should extend the dataset with the module if the model has a dataset" do
@c.dataset_module{def return_3() 3 end}
@c.dataset.return_3.must_equal 3
end
it "should also extend the instance_dataset with the module if the model has a dataset" do
@c.dataset_module{def return_3() 3 end}
@c.instance_dataset.return_3.must_equal 3
end
it "should add methods defined in the module to the class" do
@c.dataset_module{def return_3() 3 end}
@c.return_3.must_equal 3
end
it "should add methods defined in the module outside the block to the class" do
@c.dataset_module.module_eval{def return_3() 3 end}
@c.return_3.must_equal 3
end
it "should add methods that can't be called with normal method syntax as class methods" do
@c.dataset_module.module_eval{define_method(:'return 3'){3}}
@c.send(:'return 3').must_equal 3
end
it "should not add private or protected methods defined in the module to the class" do
@c.dataset_module{private; def return_3() 3 end}
@c.dataset_module{protected; def return_4() 4 end}
@c.respond_to?(:return_3).must_equal false
@c.respond_to?(:return_4).must_equal false
end
it "should cache calls and readd methods if set_dataset is used" do
@c.dataset_module{def return_3() 3 end}
@c.set_dataset :items
@c.return_3.must_equal 3
@c.dataset.return_3.must_equal 3
end
it "should readd methods to subclasses, if set_dataset is used in a subclass" do
@c.dataset_module{def return_3() 3 end}
c = Class.new(@c)
c.set_dataset :items
c.return_3.must_equal 3
c.dataset.return_3.must_equal 3
end
it "should only have a single dataset_module per class" do
@c.dataset_module{def return_3() 3 end; alias return_3 return_3}
@c.dataset_module{def return_3() 3 + (begin; super; rescue NoMethodError; 1; end) end}
@c.return_3.must_equal 4
end
it "should not have subclasses share the dataset_module" do
@c.dataset_module{def return_3() 3 end}
c = Class.new(@c)
c.dataset_module{def return_3() 3 + (begin; super; rescue NoMethodError; 1; end) end}
c.return_3.must_equal 6
end
it "should accept a module object and extend the dataset with it" do
@c.dataset_module Module.new{def return_3() 3 end}
@c.dataset.return_3.must_equal 3
end
it "should be able to call dataset_module with a module multiple times" do
@c.dataset_module Module.new{def return_3() 3 end}
@c.dataset_module Module.new{def return_4() 4 end}
@c.dataset.return_3.must_equal 3
@c.dataset.return_4.must_equal 4
end
it "should be able mix dataset_module calls with and without arguments" do
@c.dataset_module{def return_3() 3 end}
@c.dataset_module Module.new{def return_4() 4 end}
@c.dataset.return_3.must_equal 3
@c.dataset.return_4.must_equal 4
end
it "should have modules provided to dataset_module extend subclass datasets" do
@c.dataset_module{def return_3() 3 end}
@c.dataset_module Module.new{def return_4() 4 end}
c = Class.new(@c)
c.set_dataset :a
c.dataset.return_3.must_equal 3
c.dataset.return_4.must_equal 4
end
it "should return the dataset module if given a block" do
Object.new.extend(@c.dataset_module{def return_3() 3 end}).return_3.must_equal 3
end
it "should return the argument if given one" do
Object.new.extend(@c.dataset_module Module.new{def return_3() 3 end}).return_3.must_equal 3
end
it "should have dataset_module support a subset method" do
@c.dataset_module{subset :released, :released}
@c.released.sql.must_equal 'SELECT * FROM items WHERE released'
@c.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE (foo AND released)'
end
it "should have dataset_module support a where method" do
@c.dataset_module{where :released, :released}
@c.released.sql.must_equal 'SELECT * FROM items WHERE released'
@c.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE (foo AND released)'
end
if Sequel::Model.dataset_module_class == Sequel::Model::DatasetModule
it "should have dataset_module not support an eager method" do
proc{@c.dataset_module{eager :foo}}.must_raise NoMethodError
end
end
it "should have dataset_module support a having method" do
@c.dataset_module{having(:released){released}}
@c.released.sql.must_equal 'SELECT * FROM items HAVING released'
@c.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE foo HAVING released'
end
it "should have dataset_module support an exclude method" do
@c.dataset_module{exclude :released, :released}
@c.released.sql.must_equal 'SELECT * FROM items WHERE NOT released'
@c.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE (foo AND NOT released)'
end
it "should have dataset_module support an exclude_having method" do
@c.dataset_module{exclude_having :released, :released}
@c.released.sql.must_equal 'SELECT * FROM items HAVING NOT released'
@c.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE foo HAVING NOT released'
end
it "should have dataset_module support a distinct method" do
@c.dataset = @c.dataset.with_extend{def supports_distinct_on?; true end}
@c.dataset_module{distinct :foo, :baz}
@c.foo.sql.must_equal 'SELECT DISTINCT ON (baz) * FROM items'
@c.where(:bar).foo.sql.must_equal 'SELECT DISTINCT ON (baz) * FROM items WHERE bar'
end
it "should have dataset_module support a grep method" do
@c.dataset_module{grep :foo, :baz, 'quux%'}
@c.foo.sql.must_equal 'SELECT * FROM items WHERE ((baz LIKE \'quux%\' ESCAPE \'\\\'))'
@c.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE (bar AND ((baz LIKE \'quux%\' ESCAPE \'\\\')))'
end
it "should have dataset_module support a group method" do
@c.dataset_module{group :foo, :baz}
@c.foo.sql.must_equal 'SELECT * FROM items GROUP BY baz'
@c.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar GROUP BY baz'
end
it "should have dataset_module support a group_and_count method" do
@c.dataset_module{group_and_count :foo, :baz}
@c.foo.sql.must_equal 'SELECT baz, count(*) AS count FROM items GROUP BY baz'
@c.where(:bar).foo.sql.must_equal 'SELECT baz, count(*) AS count FROM items WHERE bar GROUP BY baz'
end
it "should have dataset_module support a group_append method" do
@c.dataset_module{group_append :foo, :baz}
@c.foo.sql.must_equal 'SELECT * FROM items GROUP BY baz'
@c.group(:bar).foo.sql.must_equal 'SELECT * FROM items GROUP BY bar, baz'
end
it "should have dataset_module support a limit method" do
@c.dataset_module{limit :foo, 1}
@c.foo.sql.must_equal 'SELECT * FROM items LIMIT 1'
@c.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar LIMIT 1'
end
it "should have dataset_module support a offset method" do
@c.dataset_module{offset :foo, 1}
@c.foo.sql.must_equal 'SELECT * FROM items OFFSET 1'
@c.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar OFFSET 1'
end
it "should have dataset_module support a order method" do
@c.dataset_module{order(:foo){:baz}}
@c.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
@c.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar ORDER BY baz'
end
it "should have dataset_module support a order_append method" do
@c.dataset_module{order_append :foo, :baz}
@c.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
@c.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY bar, baz'
end
it "should have dataset_module support a order_prepend method" do
@c.dataset_module{order_prepend :foo, :baz}
@c.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
@c.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY baz, bar'
end
it "should have dataset_module support a reverse method" do
@c.dataset_module{reverse(:foo){:baz}}
@c.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz DESC'
@c.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar ORDER BY baz DESC'
end
it "should have dataset_module support a select method" do
@c.dataset_module{select :foo, :baz}
@c.foo.sql.must_equal 'SELECT baz FROM items'
@c.where(:bar).foo.sql.must_equal 'SELECT baz FROM items WHERE bar'
end
it "should have dataset_module support a select_all method" do
@c.dataset_module{select_all :foo, :baz}
@c.foo.sql.must_equal 'SELECT baz.* FROM items'
@c.where(:bar).foo.sql.must_equal 'SELECT baz.* FROM items WHERE bar'
end
it "should have dataset_module support a select_append method" do
@c.dataset_module{select_append :foo, :baz}
@c.foo.sql.must_equal 'SELECT *, baz FROM items'
@c.where(:bar).foo.sql.must_equal 'SELECT *, baz FROM items WHERE bar'
end
it "should have dataset_module support a select_group method" do
@c.dataset_module{select_group :foo, :baz}
@c.foo.sql.must_equal 'SELECT baz FROM items GROUP BY baz'
@c.where(:bar).foo.sql.must_equal 'SELECT baz FROM items WHERE bar GROUP BY baz'
end
it "should have dataset_module support a server method" do
@c.dataset_module{server :foo, :baz}
@c.foo.opts[:server].must_equal :baz
@c.where(:bar).foo.opts[:server].must_equal :baz
end
it "should raise error if called with both an argument and a block" do
proc{@c.dataset_module(Module.new{def return_3() 3 end}){}}.must_raise(Sequel::Error)
end
it "should have dataset_module support a method with keyword arguments" do
@c.dataset_module { eval('def with_foo(name: (raise)); end') }
proc{@c.with_foo}.must_raise(StandardError)
end if RUBY_VERSION >= '2.0'
end
describe "A model class with implicit table name" do
before do
class ::Donkey < Sequel::Model
end
end
after do
Object.send(:remove_const, :Donkey)
end
it "should have a dataset associated with the model class" do
Donkey.dataset.model.must_equal Donkey
end
end
describe "A model inheriting from a model" do
before do
class ::Feline < Sequel::Model; end
class ::Leopard < Feline; end
end
after do
Object.send(:remove_const, :Leopard)
Object.send(:remove_const, :Feline)
end
it "should have a dataset associated with itself" do
Feline.dataset.model.must_equal Feline
Leopard.dataset.model.must_equal Leopard
end
end
describe "A model inheriting from a custom base that sets @dataset" do
before do
::Feline = Class.new(Sequel::Model)
def Feline.inherited(subclass)
subclass.instance_variable_set(:@dataset, nil)
super
end
class ::Leopard < Feline; end
end
after do
Object.send(:remove_const, :Leopard)
Object.send(:remove_const, :Feline)
end
it "should not infer the dataset of the subclass" do
proc{Leopard.dataset}.must_raise(Sequel::Error)
end
end
describe "Model.primary_key" do
before do
@c = Class.new(Sequel::Model)
end
it "should default to id" do
@c.primary_key.must_equal :id
end
it "should be overridden by set_primary_key" do
@c.set_primary_key :cid
@c.primary_key.must_equal :cid
@c.set_primary_key([:id1, :id2])
@c.primary_key.must_equal [:id1, :id2]
end
it "should use nil for no primary key" do
@c.no_primary_key
@c.primary_key.must_be_nil
end
end
describe "Model.primary_key_hash" do
before do
@c = Class.new(Sequel::Model)
end
it "should handle a single primary key" do
@c.primary_key_hash(1).must_equal(:id=>1)
end
it "should handle a composite primary key" do
@c.set_primary_key([:id1, :id2])
@c.primary_key_hash([1, 2]).must_equal(:id1=>1, :id2=>2)
end
it "should raise an error for no primary key" do
@c.no_primary_key
proc{@c.primary_key_hash(1)}.must_raise(Sequel::Error)
end
end
describe "Model.qualified_primary_key_hash" do
before do
@c = Class.new(Sequel::Model(:items))
end
it "should handle a single primary key" do
@c.qualified_primary_key_hash(1).must_equal(Sequel.qualify(:items, :id)=>1)
end
it "should handle a composite primary key" do
@c.set_primary_key([:id1, :id2])
@c.qualified_primary_key_hash([1, 2]).must_equal(Sequel.qualify(:items, :id1)=>1, Sequel.qualify(:items, :id2)=>2)
end
it "should raise an error for no primary key" do
@c.no_primary_key
proc{@c.qualified_primary_key_hash(1)}.must_raise(Sequel::Error)
end
it "should allow specifying a different qualifier" do
@c.qualified_primary_key_hash(1, :apple).must_equal(Sequel.qualify(:apple, :id)=>1)
@c.set_primary_key([:id1, :id2])
@c.qualified_primary_key_hash([1, 2], :bear).must_equal(Sequel.qualify(:bear, :id1)=>1, Sequel.qualify(:bear, :id2)=>2)
end
end
describe "Model.db" do
before do
@db = Sequel.mock
@databases = Sequel::DATABASES.dup
@model_db = Sequel::Model.db
Sequel::Model.db = nil
Sequel::DATABASES.clear
end
after do
Sequel::Model.instance_variable_get(:@db).must_be_nil
Sequel::DATABASES.replace(@databases)
Sequel::Model.db = @model_db
end
it "should be required when creating named model classes" do
begin
proc{class ModelTest < Sequel::Model; end}.must_raise(Sequel::Error)
ensure
Object.send(:remove_const, :ModelTest)
end
end
it "should be required when creating anonymous model classes without a database" do
proc{Sequel::Model(:foo)}.must_raise(Sequel::Error)
end
it "should not be required when creating anonymous model classes with a database" do
Sequel::Model(@db).db.must_equal @db
Sequel::Model(@db[:foo]).db.must_equal @db
end
it "should work correctly when subclassing anonymous model classes with a database" do
begin
Class.new(Sequel::Model(@db)).db.must_equal @db
Class.new(Sequel::Model(@db[:foo])).db.must_equal @db
class ModelTest < Sequel::Model(@db)
db.must_equal @db
end
class ModelTest2 < Sequel::Model(@db[:foo])
db.must_equal @db
end
ModelTest.instance_variable_set(:@db, nil)
ModelTest.db.must_equal @db
ensure
Object.send(:remove_const, :ModelTest)
Object.send(:remove_const, :ModelTest2)
end
end
end
describe "Model.db=" do
before do
@db1 = Sequel.mock
@db2 = Sequel.mock
@m = Class.new(Sequel::Model(@db1))
end
it "should change database for model" do
@m.db = @db2
@m.db.must_equal @db2
end
it "should raise Error for model with existing dataset" do
@m.dataset = :table
proc{@m.db = @db2}.must_raise Sequel::Error
end
it "should use the database for subclasses" do
Class.new(@m).db.must_equal @db1
end
end
describe Sequel::Model, ".(un)?restrict_primary_key\\??" do
before do
@c = Class.new(Sequel::Model(:blahblah)) do
set_primary_key :id
columns :x, :y, :z, :id
end
@c.strict_param_setting = false
end
it "should restrict updates to primary key by default" do
i = @c.new(:x => 1, :y => 2, :id => 3)
i.values.must_equal(:x => 1, :y => 2)
i.set(:x => 4, :y => 5, :id => 6)
i.values.must_equal(:x => 4, :y => 5)
end
it "should allow updates to primary key if unrestrict_primary_key is used" do
@c.unrestrict_primary_key
i = @c.new(:x => 1, :y => 2, :id => 3)
i.values.must_equal(:x => 1, :y => 2, :id=>3)
i.set(:x => 4, :y => 5, :id => 6)
i.values.must_equal(:x => 4, :y => 5, :id=>6)
end
it "should have restrict_primary_key? return true or false depending" do
@c.restrict_primary_key?.must_equal true
@c.unrestrict_primary_key
@c.restrict_primary_key?.must_equal false
c1 = Class.new(@c)
c1.restrict_primary_key?.must_equal false
@c.restrict_primary_key
@c.restrict_primary_key?.must_equal true
c1.restrict_primary_key?.must_equal false
c2 = Class.new(@c)
c2.restrict_primary_key?.must_equal true
end
end
describe Sequel::Model, ".strict_param_setting" do
before do
@c = Class.new(Sequel::Model(:blahblah)) do
columns :x, :y, :z, :id
end
end
it "should be enabled by default" do
@c.strict_param_setting.must_equal true
end
it "should raise an error if a missing/restricted column/method is accessed" do
proc{@c.new(:a=>1)}.must_raise(Sequel::MassAssignmentRestriction)
proc{@c.create(:a=>1)}.must_raise(Sequel::MassAssignmentRestriction)
c = @c.new
proc{c.set(:a=>1)}.must_raise(Sequel::MassAssignmentRestriction)
proc{c.update(:a=>1)}.must_raise(Sequel::MassAssignmentRestriction)
end
it "should be disabled by strict_param_setting = false" do
@c.strict_param_setting = false
@c.strict_param_setting.must_equal false
@c.new(:a=>1)
end
end
describe Sequel::Model, ".require_modification" do
before do
@ds1 = DB[:items].with_extend{def provides_accurate_rows_matched?; false end}
@ds2 = DB[:items].with_extend{def provides_accurate_rows_matched?; true end}
end
after do
Sequel::Model.require_modification = nil
end
it "should depend on whether the dataset provides an accurate number of rows matched by default" do
Class.new(Sequel::Model).set_dataset(@ds1).require_modification.must_equal false
Class.new(Sequel::Model).set_dataset(@ds2).require_modification.must_equal true
end
it "should obey global setting regardless of dataset support if set" do
Sequel::Model.require_modification = true
Class.new(Sequel::Model).set_dataset(@ds1).require_modification.must_equal true
Class.new(Sequel::Model).set_dataset(@ds2).require_modification.must_equal true
Sequel::Model.require_modification = false
Class.new(Sequel::Model).set_dataset(@ds1).require_modification.must_equal false
Class.new(Sequel::Model).set_dataset(@ds1).require_modification.must_equal false
end
end
describe Sequel::Model, ".[] optimization" do
before do
@db = Sequel.mock
def @db.schema(*) [[:id, {:primary_key=>true}]] end
def @db.supports_schema_parsing?() true end
@c = Class.new(Sequel::Model(@db))
@ds = @db.dataset.with_quote_identifiers(true)
end
it "should set simple_pk to the literalized primary key column name if a single primary key" do
@c.set_primary_key :id
@c.simple_pk.must_equal 'id'
@c.set_primary_key :b
@c.simple_pk.must_equal 'b'
@c.set_primary_key Sequel.identifier(:b__a)
@c.simple_pk.must_equal 'b__a'
end
it "should have simple_pk be blank if compound or no primary key" do
@c.no_primary_key
@c.simple_pk.must_be_nil
@c.set_primary_key [:b, :a]
@c.simple_pk.must_be_nil
end
it "should have simple table set if passed a Symbol to set_dataset" do
@c.set_dataset :a
@c.simple_table.must_equal 'a'
@c.set_dataset :b
@c.simple_table.must_equal 'b'
end
it "should have simple_table set if passed a simple select all dataset to set_dataset" do
@c.set_dataset @ds.from(:a)
@c.simple_table.must_equal '"a"'
@c.set_dataset @ds.from(:b)
@c.simple_table.must_equal '"b"'
@c.set_dataset @ds.from(Sequel[:b][:a])
@c.simple_table.must_equal '"b"."a"'
end
with_symbol_splitting "should have simple_table set using qualified symbol" do
@c.set_dataset :b__a
@c.simple_table.must_equal 'b.a'
@c.set_dataset @ds.from(:b__a)
@c.simple_table.must_equal '"b"."a"'
end
it "should have simple table = nil if passed an aliased expression to set_dataset" do
@c.set_dataset Sequel.as(:a, :b)
@c.simple_table.must_be_nil
end
it "should have simple table = nil if passed a literal string" do
@c.set_dataset Sequel.lit('a')
@c.simple_table.must_be_nil
end
it "should have simple_table = nil if passed a non-simple select all dataset to set_dataset" do
@c.set_dataset @c.db[:a].filter(:active)
@c.simple_table.must_be_nil
end
it "should have simple_table inherit superclass's setting" do
Class.new(@c).simple_table.must_be_nil
@c.set_dataset :a
Class.new(@c).simple_table.must_equal 'a'
end
it "should use Dataset#with_sql if simple_table and simple_pk are true" do
@c.set_dataset @db[:a].with_fetch(:id=>1)
@c[1].must_equal @c.load(:id=>1)
@db.sqls.must_equal ['SELECT * FROM a WHERE id = 1']
end
it "should use Dataset#with_sql if simple_table and simple_pk are true" do
@c.set_dataset @db[:a].with_fetch(:id=>1).with_extend{def supports_placeholder_literalizer?; false end}
@c[1].must_equal @c.load(:id=>1)
@db.sqls.must_equal ['SELECT * FROM a WHERE (id = 1) LIMIT 1']
end
it "should not use Dataset#with_sql if either simple_table or simple_pk is nil" do
@c.set_dataset @db[:a].where(:active).with_fetch(:id=>1)
@c[1].must_equal @c.load(:id=>1)
@db.sqls.must_equal ['SELECT * FROM a WHERE (active AND (id = 1)) LIMIT 1']
end
it "should return first matching record for hash argument" do
@c.set_dataset @db[:a].with_fetch(:id=>1, :a=>2)
@c[:a=>2].values.must_equal(:id=>1, :a=>2)
@db.sqls.must_equal ['SELECT * FROM a WHERE (a = 2) LIMIT 1']
end
it "should return nil for nil argument" do
@c[nil].must_be_nil
@db.sqls.must_equal []
end
end
describe "Model datasets #with_pk with #with_pk!" do
before do
@c = Class.new(Sequel::Model(:a))
@ds = @c.dataset = @c.dataset.with_fetch(:id=>1)
DB.reset
end
it "should be callable on the model class with optimized SQL" do
@c.with_pk(1).must_equal @c.load(:id=>1)
DB.sqls.must_equal ["SELECT * FROM a WHERE id = 1"]
@c.with_pk!(1).must_equal @c.load(:id=>1)
DB.sqls.must_equal ["SELECT * FROM a WHERE id = 1"]
end
it "should return the first record where the primary key matches" do
@ds.with_pk(1).must_equal @c.load(:id=>1)
DB.sqls.must_equal ["SELECT * FROM a WHERE (a.id = 1) LIMIT 1"]
@ds.with_pk!(1).must_equal @c.load(:id=>1)
DB.sqls.must_equal ["SELECT * FROM a WHERE (a.id = 1) LIMIT 1"]
end
it "should work when called repeatedly on a frozen dataset" do
@ds.freeze
5.times do
@ds.with_pk(1).must_equal @c.load(:id=>1)
DB.sqls.must_equal ["SELECT * FROM a WHERE (a.id = 1) LIMIT 1"]
end
end
it "should handle existing filters" do
@ds.filter(:a=>2).with_pk(1)
DB.sqls.must_equal ["SELECT * FROM a WHERE ((a = 2) AND (a.id = 1)) LIMIT 1"]
@ds.filter(:a=>2).with_pk!(1)
DB.sqls.must_equal ["SELECT * FROM a WHERE ((a = 2) AND (a.id = 1)) LIMIT 1"]
end
it "should work with string values" do
@ds.with_pk("foo")
DB.sqls.must_equal ["SELECT * FROM a WHERE (a.id = 'foo') LIMIT 1"]
@ds.with_pk!("foo")
DB.sqls.must_equal ["SELECT * FROM a WHERE (a.id = 'foo') LIMIT 1"]
end
it "should handle an array for composite primary keys" do
@c.set_primary_key [:id1, :id2]
@ds.with_pk([1, 2])
DB.sqls.must_equal ["SELECT * FROM a WHERE ((a.id1 = 1) AND (a.id2 = 2)) LIMIT 1"]
@ds.with_pk!([1, 2])
DB.sqls.must_equal ["SELECT * FROM a WHERE ((a.id1 = 1) AND (a.id2 = 2)) LIMIT 1"]
end
it "should work with composite primary keys when called repeatedly on a frozen dataset with" do
@c.set_primary_key [:id1, :id2]
@ds.freeze
5.times do
@ds.with_pk([1,2])
DB.sqls.must_equal ["SELECT * FROM a WHERE ((a.id1 = 1) AND (a.id2 = 2)) LIMIT 1"]
end
end
it "should have with_pk return nil and with_pk! raise if no rows match" do
@ds = @ds.with_fetch([])
@ds.with_pk(1).must_be_nil
DB.sqls.must_equal ["SELECT * FROM a WHERE (a.id = 1) LIMIT 1"]
proc{@ds.with_pk!(1)}.must_raise(Sequel::NoMatchingRow)
DB.sqls.must_equal ["SELECT * FROM a WHERE (a.id = 1) LIMIT 1"]
end
it "should have with_pk return nil and with_pk! raise if no rows match when calling the class method" do
@c.dataset = @c.dataset.with_fetch([])
@c.with_pk(1).must_be_nil
DB.sqls.must_equal ["SELECT * FROM a WHERE id = 1"]
proc{@c.with_pk!(1)}.must_raise(Sequel::NoMatchingRow)
DB.sqls.must_equal ["SELECT * FROM a WHERE id = 1"]
end
it "should have #[] consider an integer as a primary key lookup" do
@ds[1].must_equal @c.load(:id=>1)
DB.sqls.must_equal ["SELECT * FROM a WHERE (a.id = 1) LIMIT 1"]
end
it "should not have #[] consider a literal string as a primary key lookup" do
@ds[Sequel.lit('foo')].must_equal @c.load(:id=>1)
DB.sqls.must_equal ["SELECT * FROM a WHERE (foo) LIMIT 1"]
end
it "should raise Error if called on a dataset with no primary key" do
@c.no_primary_key
@ds.freeze
5.times do
proc{@ds.with_pk(1)}.must_raise Sequel::Error
end
end
end
describe "Model::include" do
it "shouldn't change the signature of Module::include" do
mod1 = Module.new
mod2 = Module.new
including_class = Class.new(Sequel::Model(:items)) do
include(mod1, mod2)
end
including_class.included_modules.must_include(mod1)
including_class.included_modules.must_include(mod2)
end
end
|