sequel 3.37.0 → 3.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/CHANGELOG +56 -0
  2. data/README.rdoc +82 -58
  3. data/Rakefile +6 -5
  4. data/bin/sequel +1 -1
  5. data/doc/active_record.rdoc +67 -52
  6. data/doc/advanced_associations.rdoc +33 -48
  7. data/doc/association_basics.rdoc +41 -51
  8. data/doc/cheat_sheet.rdoc +21 -21
  9. data/doc/core_extensions.rdoc +374 -0
  10. data/doc/dataset_basics.rdoc +5 -5
  11. data/doc/dataset_filtering.rdoc +47 -43
  12. data/doc/mass_assignment.rdoc +1 -1
  13. data/doc/migration.rdoc +4 -5
  14. data/doc/model_hooks.rdoc +3 -3
  15. data/doc/object_model.rdoc +31 -25
  16. data/doc/opening_databases.rdoc +19 -5
  17. data/doc/prepared_statements.rdoc +2 -2
  18. data/doc/querying.rdoc +109 -52
  19. data/doc/reflection.rdoc +6 -6
  20. data/doc/release_notes/3.38.0.txt +234 -0
  21. data/doc/schema_modification.rdoc +22 -13
  22. data/doc/sharding.rdoc +8 -9
  23. data/doc/sql.rdoc +154 -112
  24. data/doc/testing.rdoc +47 -7
  25. data/doc/thread_safety.rdoc +1 -1
  26. data/doc/transactions.rdoc +1 -1
  27. data/doc/validations.rdoc +1 -1
  28. data/doc/virtual_rows.rdoc +29 -43
  29. data/lib/sequel/adapters/do/postgres.rb +1 -4
  30. data/lib/sequel/adapters/jdbc.rb +14 -3
  31. data/lib/sequel/adapters/jdbc/db2.rb +9 -0
  32. data/lib/sequel/adapters/jdbc/derby.rb +41 -4
  33. data/lib/sequel/adapters/jdbc/jtds.rb +11 -0
  34. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -6
  35. data/lib/sequel/adapters/mock.rb +10 -4
  36. data/lib/sequel/adapters/postgres.rb +1 -28
  37. data/lib/sequel/adapters/shared/mssql.rb +23 -13
  38. data/lib/sequel/adapters/shared/postgres.rb +46 -0
  39. data/lib/sequel/adapters/swift.rb +21 -13
  40. data/lib/sequel/adapters/swift/mysql.rb +1 -0
  41. data/lib/sequel/adapters/swift/postgres.rb +4 -5
  42. data/lib/sequel/adapters/swift/sqlite.rb +2 -1
  43. data/lib/sequel/adapters/tinytds.rb +14 -2
  44. data/lib/sequel/adapters/utils/pg_types.rb +5 -0
  45. data/lib/sequel/core.rb +29 -17
  46. data/lib/sequel/database/query.rb +1 -1
  47. data/lib/sequel/database/schema_generator.rb +3 -0
  48. data/lib/sequel/dataset/actions.rb +5 -6
  49. data/lib/sequel/dataset/query.rb +7 -7
  50. data/lib/sequel/dataset/sql.rb +5 -18
  51. data/lib/sequel/extensions/core_extensions.rb +8 -12
  52. data/lib/sequel/extensions/pg_array.rb +59 -33
  53. data/lib/sequel/extensions/pg_array_ops.rb +32 -4
  54. data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
  55. data/lib/sequel/extensions/pg_hstore.rb +32 -17
  56. data/lib/sequel/extensions/pg_hstore_ops.rb +32 -3
  57. data/lib/sequel/extensions/pg_inet.rb +1 -2
  58. data/lib/sequel/extensions/pg_interval.rb +0 -1
  59. data/lib/sequel/extensions/pg_json.rb +41 -23
  60. data/lib/sequel/extensions/pg_range.rb +36 -11
  61. data/lib/sequel/extensions/pg_range_ops.rb +32 -4
  62. data/lib/sequel/extensions/pg_row.rb +572 -0
  63. data/lib/sequel/extensions/pg_row_ops.rb +164 -0
  64. data/lib/sequel/extensions/query.rb +3 -3
  65. data/lib/sequel/extensions/schema_dumper.rb +7 -8
  66. data/lib/sequel/extensions/select_remove.rb +1 -1
  67. data/lib/sequel/model/base.rb +1 -0
  68. data/lib/sequel/no_core_ext.rb +1 -1
  69. data/lib/sequel/plugins/pg_row.rb +121 -0
  70. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  71. data/lib/sequel/plugins/validation_helpers.rb +31 -0
  72. data/lib/sequel/sql.rb +64 -44
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/mssql_spec.rb +37 -12
  75. data/spec/adapters/mysql_spec.rb +39 -75
  76. data/spec/adapters/oracle_spec.rb +11 -11
  77. data/spec/adapters/postgres_spec.rb +414 -237
  78. data/spec/adapters/spec_helper.rb +1 -1
  79. data/spec/adapters/sqlite_spec.rb +14 -14
  80. data/spec/core/database_spec.rb +6 -6
  81. data/spec/core/dataset_spec.rb +169 -205
  82. data/spec/core/expression_filters_spec.rb +182 -295
  83. data/spec/core/object_graph_spec.rb +6 -6
  84. data/spec/core/schema_spec.rb +14 -14
  85. data/spec/core/spec_helper.rb +1 -0
  86. data/spec/{extensions/core_extensions_spec.rb → core_extensions_spec.rb} +208 -14
  87. data/spec/extensions/columns_introspection_spec.rb +5 -5
  88. data/spec/extensions/hook_class_methods_spec.rb +28 -36
  89. data/spec/extensions/many_through_many_spec.rb +4 -4
  90. data/spec/extensions/pg_array_ops_spec.rb +15 -7
  91. data/spec/extensions/pg_array_spec.rb +81 -48
  92. data/spec/extensions/pg_auto_parameterize_spec.rb +2 -2
  93. data/spec/extensions/pg_hstore_ops_spec.rb +13 -9
  94. data/spec/extensions/pg_hstore_spec.rb +66 -65
  95. data/spec/extensions/pg_inet_spec.rb +2 -4
  96. data/spec/extensions/pg_interval_spec.rb +2 -3
  97. data/spec/extensions/pg_json_spec.rb +20 -18
  98. data/spec/extensions/pg_range_ops_spec.rb +11 -4
  99. data/spec/extensions/pg_range_spec.rb +30 -7
  100. data/spec/extensions/pg_row_ops_spec.rb +48 -0
  101. data/spec/extensions/pg_row_plugin_spec.rb +45 -0
  102. data/spec/extensions/pg_row_spec.rb +323 -0
  103. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  104. data/spec/extensions/query_literals_spec.rb +11 -11
  105. data/spec/extensions/query_spec.rb +3 -3
  106. data/spec/extensions/schema_dumper_spec.rb +20 -4
  107. data/spec/extensions/schema_spec.rb +18 -41
  108. data/spec/extensions/select_remove_spec.rb +4 -4
  109. data/spec/extensions/spec_helper.rb +4 -8
  110. data/spec/extensions/to_dot_spec.rb +5 -5
  111. data/spec/extensions/validation_class_methods_spec.rb +28 -16
  112. data/spec/integration/associations_test.rb +20 -20
  113. data/spec/integration/dataset_test.rb +98 -98
  114. data/spec/integration/eager_loader_test.rb +13 -27
  115. data/spec/integration/plugin_test.rb +5 -5
  116. data/spec/integration/prepared_statement_test.rb +22 -13
  117. data/spec/integration/schema_test.rb +28 -18
  118. data/spec/integration/spec_helper.rb +1 -1
  119. data/spec/integration/timezone_test.rb +2 -2
  120. data/spec/integration/type_test.rb +15 -6
  121. data/spec/model/association_reflection_spec.rb +1 -1
  122. data/spec/model/associations_spec.rb +4 -4
  123. data/spec/model/base_spec.rb +5 -5
  124. data/spec/model/eager_loading_spec.rb +15 -15
  125. data/spec/model/model_spec.rb +32 -32
  126. data/spec/model/record_spec.rb +16 -0
  127. data/spec/model/spec_helper.rb +2 -6
  128. data/spec/model/validations_spec.rb +1 -1
  129. metadata +16 -4
@@ -345,7 +345,7 @@ The association dataset is just like any other Sequel dataset, in that
345
345
  it can be further filtered, ordered, etc.:
346
346
 
347
347
  @artist.albums_dataset.
348
- filter(:name.like('A%')).
348
+ where(Sequel.like(:name, 'A%')).
349
349
  order(:copies_sold).
350
350
  limit(10)
351
351
  # SELECT * FROM albums
@@ -364,8 +364,8 @@ Similar to the +_dataset+ method, you can provide a block to the association
364
364
  method to customize the dataset that will be used to retrieve the records. So
365
365
  you can apply a filter in either of these two ways:
366
366
 
367
- @artist.albums_dataset.filter(:name.like('A%'))
368
- @artist.albums{|ds| ds.filter(:name.like('A%'))}
367
+ @artist.albums_dataset.where(Sequel.like(:name, 'A%'))
368
+ @artist.albums{|ds| ds.where(Sequel.like(:name, 'A%'))}
369
369
 
370
370
  While they both apply the same filter, using the +_dataset+ method does not
371
371
  apply any of the association callbacks or handle association reciprocals (see
@@ -373,11 +373,6 @@ below for details about callbacks and reciprocals). Using a block instead handl
373
373
  all those things, and also caches its results in the associations cache (ignoring
374
374
  any previously cached value).
375
375
 
376
- Note that if you are using ruby 1.8.6, you can't pass a block to the association
377
- method, you have to pass a proc as an argument:
378
-
379
- @artist.albums(proc{|ds| ds.filter(:name.like('A%'))})
380
-
381
376
  == Filtering By Associations
382
377
 
383
378
  In addition to using the association method to get associated objects, you
@@ -389,35 +384,35 @@ all albums for a given artist, you would usually do:
389
384
 
390
385
  You can also do the following:
391
386
 
392
- Album.filter(:artist=>@artist).all
387
+ Album.where(:artist=>@artist).all
393
388
  # or leave off the .all for a dataset
394
389
 
395
390
  For filtering by a single association, this isn't very useful. However, unlike
396
391
  using the association method, using a filter allows you to filter by multiple
397
392
  associations:
398
393
 
399
- Album.filter(:artist=>@artist, :publisher=>@publisher)
394
+ Album.where(:artist=>@artist, :publisher=>@publisher)
400
395
 
401
396
  This will return all albums by that artist and published by that publisher.
402
397
  This isn't possible using just the association method approach, though you
403
398
  can combine the approaches:
404
399
 
405
- @artist.albums_dataset.filter(:publisher=>@publisher)
400
+ @artist.albums_dataset.where(:publisher=>@publisher)
406
401
 
407
402
  This doesn't just work for +many_to_one+ associations, it also works for
408
403
  +one_to_one+, +one_to_many+, and +many_to_many+ associations:
409
404
 
410
405
  Album.one_to_one :album_info
411
406
  # The album related to that AlbumInfo instance
412
- Album.filter(:album_info=>AlbumInfo[2])
407
+ Album.where(:album_info=>AlbumInfo[2])
413
408
 
414
409
  Album.one_to_many :tracks
415
410
  # The album related to that Track instance
416
- Album.filter(:tracks=>Track[3])
411
+ Album.where(:tracks=>Track[3])
417
412
 
418
413
  Album.many_to_many :tags
419
414
  # All albums related to that Tag instance
420
- Album.filter(:tags=>Tag[4])
415
+ Album.where(:tags=>Tag[4])
421
416
 
422
417
  Note that for +one_to_many+ and +many_to_many+ associations, you still
423
418
  use the plural form even though only a single model object is given.
@@ -430,7 +425,7 @@ This will return all albums not by that artist.
430
425
 
431
426
  You can also provide an array with multiple model objects:
432
427
 
433
- Album.filter(:artist=>[@artist1, @artist2]).all
428
+ Album.where(:artist=>[@artist1, @artist2]).all
434
429
 
435
430
  Similar to using an array of integers or strings, this will return
436
431
  all albums whose artist is one of those two artists. You can also
@@ -442,28 +437,28 @@ If you are using a +one_to_many+ or +many_to_many+ association, you
442
437
  may want to return records where the records matches all of multiple
443
438
  records, instead of matching any of them. For example:
444
439
 
445
- Album.filter(:tags=>[@tag1, @tag2])
440
+ Album.where(:tags=>[@tag1, @tag2])
446
441
 
447
442
  This matches albums that are associated with either @tag1 or @tag2 or
448
443
  both. If you only want ones that you are associated with both, you can
449
444
  use separate filter calls:
450
445
 
451
- Album.filter(:tags=>@tag1).filter(:tags=>@tag2)
446
+ Album.where(:tags=>@tag1).where(:tags=>@tag2)
452
447
 
453
448
  Or the the array form of condition specifiers:
454
449
 
455
- Album.filter([[:tags, @tag1], [:tags, @tag2]])
450
+ Album.where([[:tags, @tag1], [:tags, @tag2]])
456
451
 
457
452
  These will return albums associated with both @tag1 and @tag2.
458
453
 
459
454
  You can also provide a dataset value when filtering by associations:
460
455
 
461
- Album.filter(:artist=>Artist.filter(:name.like('A%'))).all
456
+ Album.where(:artist=>Artist.where(Sequel.like(:name, 'A%'))).all
462
457
 
463
458
  This will return all albums whose artist starts with 'A'. Like
464
459
  the other forms, this can be inverted:
465
460
 
466
- Album.exclude(:artist=>Artist.filter(:name.like('A%'))).all
461
+ Album.exclude(:artist=>Artist.where(Sequel.like(:name, 'A%'))).all
467
462
 
468
463
  This will return all albums whose artist does not start with 'A'.
469
464
 
@@ -562,6 +557,8 @@ wanted to add an albums_artists join table to create the following schema:
562
557
 
563
558
  You could use the following Sequel code:
564
559
 
560
+ DB.create_join_table(:album_id=>:albums, :artist_id=>:artists)
561
+ # or
565
562
  DB.create_table(:albums_artists) do
566
563
  foreign_key :album_id, :albums
567
564
  foreign_key :artist_id, :artists
@@ -717,7 +714,7 @@ The <i>association</i>_dataset method returns a dataset that represents
717
714
  all associated objects. This dataset is like any other Sequel dataset,
718
715
  in that it can be filtered, ordered, etc.:
719
716
 
720
- ds = @artist.albums_dataset.filter(:name.like('A%')).order(:copies_sold)
717
+ ds = @artist.albums_dataset.where(Sequel.like(:name, 'A%')).order(:copies_sold)
721
718
 
722
719
  Unlike most other Sequel datasets, association datasets have a couple of
723
720
  added methods:
@@ -828,7 +825,7 @@ that returns all albums of an artist that went gold (sold at least
828
825
  500,000 copies):
829
826
 
830
827
  Artist.one_to_many :gold_albums, :class=>:Album do |ds|
831
- ds.filter{copies_sold > 500000}
828
+ ds.where{copies_sold > 500000}
832
829
  end
833
830
 
834
831
  ==== :class
@@ -847,7 +844,7 @@ default class guessed will be wrong:
847
844
 
848
845
  # guesses GoldAlbum
849
846
  Artist.one_to_many :gold_albums do |ds|
850
- ds.filter{copies_sold > 500000}
847
+ ds.where{copies_sold > 500000}
851
848
  end
852
849
 
853
850
  You can specify the :class option using the class itself, a Symbol,
@@ -872,13 +869,13 @@ symbol. Defaults to :"#{self.name.underscore}_id".
872
869
 
873
870
  Artist.one_to_many :albums # :key=>:artist_id
874
871
 
875
- In both cases an array of symbols for a composite key association:
872
+ In both cases an array of symbols can be used for a composite key association:
876
873
 
877
874
  Apartment.many_to_one :building # :key=>[:city, :address]
878
875
 
879
876
  ==== :conditions
880
877
 
881
- The conditions to use to filter the association, can be any argument passed to filter.
878
+ The conditions to use to filter the association, can be any argument passed to +where+.
882
879
  If you use a hash or an array of two element arrays, this will also be used as a
883
880
  filter when using eager_graph to load the association.
884
881
 
@@ -911,7 +908,7 @@ columns that have the same name in both the join table and the associated
911
908
  table. Example:
912
909
 
913
910
  Artist.one_to_many :albums, :select=>[:id, :name]
914
- Album.many_to_many :tags, :select=>[:tags.*, :albums_tags__number]
911
+ Album.many_to_many :tags, :select=>[Sequel.expr(:tags).*, :albums_tags__number]
915
912
 
916
913
  ==== :limit
917
914
 
@@ -928,8 +925,6 @@ Use an array with two arguments for the value to specify a limit and an offset.
928
925
  This probably doesn't make a lot of sense for *_to_one associations, though you
929
926
  could use it to specify an offset.
930
927
 
931
- This option is ignored when eager loading.
932
-
933
928
  ==== :join_table [+many_to_many+]
934
929
 
935
930
  Name of table that includes the foreign keys to both the current model and the
@@ -944,7 +939,7 @@ Here's an example of the defaults:
944
939
  ==== :left_key [+many_to_many+]
945
940
 
946
941
  Foreign key in join table that points to current model's primary key, as a
947
- symbol. Defaults to :"#{self.name.underscore}_id".
942
+ symbol. Defaults to :"#{model_name.underscore}_id".
948
943
 
949
944
  Album.many_to_many :tags # :left_key=>:album_id
950
945
 
@@ -953,9 +948,9 @@ Can use an array of symbols for a composite key association.
953
948
  ==== :right_key [+many_to_many+]
954
949
 
955
950
  Foreign key in join table that points to associated model's primary key, as a
956
- symbol. Defaults to :"#{name.to_s.singularize}_id".
951
+ symbol. Defaults to :"#{association_name.singularize}_id".
957
952
 
958
- Album.many_to_many :tags # :left_key=>:tag_id
953
+ Album.many_to_many :tags # :right_key=>:tag_id
959
954
 
960
955
  Can use an array of symbols for a composite key association.
961
956
 
@@ -1006,7 +1001,7 @@ Here's an example of an association of songs to artists through lyrics, where
1006
1001
  the artist can perform any one of four tasks for the lyric:
1007
1002
 
1008
1003
  Album.one_to_many :songs, :dataset=>(proc do
1009
- Song.select(:songs.*).
1004
+ Song.select_all(:songs).
1010
1005
  join(Lyric, :id=>:lyricid,
1011
1006
  id=>[:composer_id, :arranger_id, :vocalist_id, :lyricist_id])
1012
1007
  end)
@@ -1025,8 +1020,8 @@ set up association extensions. For more information , please see the
1025
1020
  ==== :primary_key
1026
1021
 
1027
1022
  The column that the :key option references, as a symbol. For +many_to_one+
1028
- associations, this column in the associated table. For +one_to_one+ and
1029
- +one_to_many+ associations, this column in the current table. In both cases,
1023
+ associations, this column is in the associated table. For +one_to_one+ and
1024
+ +one_to_many+ associations, this column is in the current table. In both cases,
1030
1025
  it defaults to the primary key of the table. Can use an
1031
1026
  array of symbols for a composite key association.
1032
1027
 
@@ -1063,7 +1058,7 @@ applies to the join table. It can be used to make sure additional columns are
1063
1058
  used when inserting, or that filters are used when deleting.
1064
1059
 
1065
1060
  Artist.many_to_many :lead_guitar_albums, :join_table_block=>proc do |ds|
1066
- ds.filter(:instrument_id=>5).set_overrides(:instrument_id=>5)
1061
+ ds.where(:instrument_id=>5).set_overrides(:instrument_id=>5)
1067
1062
  end
1068
1063
 
1069
1064
  === Callback Options
@@ -1158,8 +1153,7 @@ Called after the _<i>association</i>= method is called to modify the objects:
1158
1153
 
1159
1154
  ==== :after_load
1160
1155
 
1161
- Called after retrieving the associated records from the database. Not called
1162
- when eager loading via eager_graph, but called when eager loading via eager.
1156
+ Called after retrieving the associated records from the database.
1163
1157
 
1164
1158
  class Artist
1165
1159
  # Cache all album names to a single string when retrieving the
@@ -1176,8 +1170,7 @@ when eager loading via eager_graph, but called when eager loading via eager.
1176
1170
  end
1177
1171
 
1178
1172
  Generally used if you know you will always want a certain action done
1179
- when retrieving the association. However, you need to be careful if you
1180
- also plan on using eager_graph to eagerly load the association.
1173
+ when retrieving the association.
1181
1174
 
1182
1175
  For +one_to_many+ and +many_to_many+ associations, both the argument to
1183
1176
  symbol callbacks and the second argument to proc callbacks will be an
@@ -1242,7 +1235,7 @@ association based on dependent associations:
1242
1235
 
1243
1236
  Artist.one_to_many :albums_with_short_tracks, :class=>:Album,
1244
1237
  :eager_graph=>:tracks do |ds|
1245
- ds.filter{tracks__seconds < 120}
1238
+ ds.where{tracks__seconds < 120}
1246
1239
  end
1247
1240
  Artist.one_to_many :albums_by_track_name, :class=>:Album,
1248
1241
  :eager_graph=>:tracks do |ds|
@@ -1274,13 +1267,13 @@ via eager_graph. This is useful to specify conditions that can't be specified
1274
1267
  in a hash or array of two element arrays.
1275
1268
 
1276
1269
  Artist.one_to_many :gold_albums, :class=>:Album,
1277
- :graph_block=>proc{|j,lj,js| :copies_sold.qualify(j) > 500000}
1270
+ :graph_block=>proc{|j,lj,js| Sequel.qualify(j, :copies_sold) > 500000}
1278
1271
 
1279
1272
  ==== :graph_join_type
1280
1273
 
1281
1274
  The type of SQL join to use when eagerly loading the association via
1282
1275
  eager_graph. Defaults to :left_outer. This is useful if you want to
1283
- ensure that all return only artists that have albums:
1276
+ ensure that only artists that have albums are returned:
1284
1277
 
1285
1278
  Artist.one_to_many :albums, :graph_join_type=>:inner
1286
1279
  # Will exclude artists without an album
@@ -1306,8 +1299,8 @@ where the artist's name differs in case:
1306
1299
 
1307
1300
  Artist.one_to_many :albums, :key=>:artist_name,
1308
1301
  :graph_only_conditions=>nil,
1309
- :graph_block=>proc{|j,lj,js| {:lower.sql_function(artist_name.qualify(j))=>
1310
- :lower.sql_function(name.qualify(lj))}}
1302
+ :graph_block=>proc{|j,lj,js| {Sequel.function(:lower, Sequel.qualify(j, :artist_name))=>
1303
+ Sequel.function(:lower, Sequel.qualify(lj, :name))}}
1311
1304
 
1312
1305
  Note how :graph_only_conditions is set to nil to ignore any existing conditions,
1313
1306
  and :graph_block is used to set up the case insensitive comparison.
@@ -1345,8 +1338,8 @@ Sets up a custom grapher to use when eager loading the objects via eager_graph.
1345
1338
  This is the eager_graph analogue to the :eager_loader option. This isn't generally
1346
1339
  needed, as one of the other eager_graph related association options is usually sufficient.
1347
1340
 
1348
- If specified, should be a proc that accepts one or three three arguments.
1349
- If the proc takes one argument, it will be given a hash with the following keys:
1341
+ If specified, should be a proc that accepts a single hash argument, which will contain
1342
+ at least the following keys:
1350
1343
 
1351
1344
  :self :: The dataset that is doing the eager loading
1352
1345
  :table_alias :: An alias to use for the table to graph for this association.
@@ -1355,10 +1348,7 @@ If the proc takes one argument, it will be given a hash with the following keys:
1355
1348
  current dataset, before such graphing is done. This is nil if no callback
1356
1349
  proc is used.
1357
1350
 
1358
- If the proc takes three arguments, it gets passed the :self, :association_alias,
1359
- and :table_alias values. The 3 argument procs are allowed for backwards
1360
- compatibility, and it is recommended to use the 1 argument proc format
1361
- for new code.
1351
+ Example:
1362
1352
 
1363
1353
  Artist.one_to_many :self_title_albums, :class=>:Album,
1364
1354
  :eager_grapher=>(proc do |eo|
@@ -1407,7 +1397,7 @@ has received a bachelor's degree (degree starting with B):
1407
1397
 
1408
1398
  Person.many_to_many :bachelor_degree_colleges, :class=>:College,
1409
1399
  :join_table=>:degrees_received,
1410
- :graph_join_table_block=>proc{|j,lj,js| :degree.qualify(j).like('B%')}
1400
+ :graph_join_table_block=>proc{|j,lj,js| Sequel.qualify(j, :degree).like('B%')}
1411
1401
 
1412
1402
  This should be done when graphing the join table, instead of when graphing the
1413
1403
  final table, as :degree is a column of the join table.
data/doc/cheat_sheet.rdoc CHANGED
@@ -53,8 +53,8 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
53
53
 
54
54
  == Update/Delete rows
55
55
 
56
- dataset.filter(~:active).delete
57
- dataset.filter('price < ?', 100).update(:active => true)
56
+ dataset.exclude(:active).delete
57
+ dataset.where('price < ?', 100).update(:active => true)
58
58
 
59
59
  == Datasets are Enumerable
60
60
 
@@ -64,21 +64,21 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
64
64
  dataset.inject(0){|sum, r| sum + r[:value]}
65
65
  dataset.sum(:value) # same as above
66
66
 
67
- == Filtering (see also doc/dataset_filtering.rdoc)
67
+ == Filtering (see also {Dataset Filtering}[link:files/doc/dataset_filtering_rdoc.html])
68
68
 
69
69
  === Equality
70
70
 
71
- dataset.filter(:name => 'abc')
72
- dataset.filter('name = ?', 'abc')
71
+ dataset.where(:name => 'abc')
72
+ dataset.where('name = ?', 'abc')
73
73
 
74
74
  === Inequality
75
75
 
76
- dataset.filter{value > 100}
76
+ dataset.where{value > 100}
77
77
  dataset.exclude{value <= 100}
78
78
 
79
79
  === Inclusion
80
80
 
81
- dataset.filter(:value => 50..100)
81
+ dataset.where(:value => 50..100)
82
82
  dataset.where{(value >= 50) & (value <= 100)}
83
83
 
84
84
  dataset.where('value IN ?', [50,75,100])
@@ -89,34 +89,34 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
89
89
  === Subselects as scalar values
90
90
 
91
91
  dataset.where('price > (SELECT avg(price) + 100 FROM table)')
92
- dataset.filter{price > dataset.select(avg(price) + 100)}
92
+ dataset.where{price > dataset.select(avg(price) + 100)}
93
93
 
94
94
  === LIKE/Regexp
95
95
 
96
- DB[:items].filter(:name.like('AL%'))
97
- DB[:items].filter(:name => /^AL/)
96
+ DB[:items].where(Sequel.like(:name, 'AL%'))
97
+ DB[:items].where(:name => /^AL/)
98
98
 
99
99
  === AND/OR/NOT
100
100
 
101
- DB[:items].filter{(x > 5) & (y > 10)}.sql
101
+ DB[:items].where{(x > 5) & (y > 10)}.sql
102
102
  # SELECT * FROM items WHERE ((x > 5) AND (y > 10))
103
103
 
104
- DB[:items].filter({:x => 1, :y => 2}.sql_or & ~{:z => 3}).sql
104
+ DB[:items].where({:x => 1, :y => 2}.sql_or & Sequel.~(:z => 3)).sql
105
105
  # SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3))
106
106
 
107
107
  === Mathematical operators
108
108
 
109
- DB[:items].filter((:x + :y) > :z).sql
109
+ DB[:items].where{x + y > z}.sql
110
110
  # SELECT * FROM items WHERE ((x + y) > z)
111
111
 
112
- DB[:items].filter{price - 100 < avg(price)}.sql
112
+ DB[:items].where{price - 100 < avg(price)}.sql
113
113
  # SELECT * FROM items WHERE ((price - 100) < avg(price))
114
114
 
115
115
  == Ordering
116
116
 
117
117
  dataset.order(:kind)
118
118
  dataset.reverse_order(:kind)
119
- dataset.order(:kind.desc, :name)
119
+ dataset.order(Sequel.desc(:kind), :name)
120
120
 
121
121
  == Limit/Offset
122
122
 
@@ -140,15 +140,15 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
140
140
  dataset.sum(:stock)
141
141
 
142
142
  dataset.group_and_count(:category)
143
- dataset.group(:category).select(:category, :AVG.sql_function(:price))
143
+ dataset.group(:category).select(:category, Sequel.function(:AVG, :price))
144
144
 
145
145
  == SQL Functions / Literals
146
146
 
147
- dataset.update(:updated_at => :NOW.sql_function)
148
- dataset.update(:updated_at => 'NOW()'.lit)
147
+ dataset.update(:updated_at => Sequel.function(:NOW))
148
+ dataset.update(:updated_at => Sequel.lit('NOW()'))
149
149
 
150
- dataset.update(:updated_at => "DateValue('1/1/2001')".lit)
151
- dataset.update(:updated_at => :DateValue.sql_function('1/1/2001'))
150
+ dataset.update(:updated_at => Sequel.lit("DateValue('1/1/2001')")
151
+ dataset.update(:updated_at => Sequel.function(:DateValue, '1/1/2001'))
152
152
 
153
153
  == Schema Manipulation
154
154
 
@@ -171,7 +171,7 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
171
171
 
172
172
  == Aliasing
173
173
 
174
- DB[:items].select(:name.as(:item_name))
174
+ DB[:items].select(Sequel.as(:name, :item_name))
175
175
  DB[:items].select(:name___item_name)
176
176
  DB[:items___items_table].select(:items_table__name___item_name)
177
177
  # SELECT items_table.name AS item_name FROM items AS items_table
@@ -0,0 +1,374 @@
1
+ = Sequel's Core Extensions
2
+
3
+ == Background
4
+
5
+ Historically, Sequel added methods to many of the core classes, and usage of those methods was the primary and recommended way to use Sequel. For example:
6
+
7
+ DB[:table].select(:column.cast(Integer)). # Symbol#cast
8
+ where(:column.like('A%')). # Symbol#like
9
+ order({1=>2}.case(0, :a)) # Hash#case
10
+
11
+ While Sequel never override any methods defined by ruby, it is possible that other libraries could define the same methods that Sequel defines, which could cause problems. Also, some rubyists do not like using libraries that add methods to the core classes.
12
+
13
+ Alternatives for the core extension methods where added to Sequel, so the query above could be written as:
14
+
15
+ DB[:table].select(Sequel.cast(:column, Integer)).
16
+ where(Sequel.like(:column, 'A%')).
17
+ order(Sequel.case({1=>2}, 0, :a))
18
+
19
+ Almost all of the core extension methods have a replacement on the Sequel module. So it is now up to the user which style to use. Using the methods on the Sequel module results in slightly more verbose code, but allows the code to work without modifications to the core classes.
20
+
21
+ == Issues
22
+
23
+ There is no recommendation on whether the core_extensions should be used or not. It is very rare that any of the methods added by core_extensions actually causes a problem, but some of them can make it more difficult to find other problems. For example, if you type:
24
+
25
+ do_somehting if value | other_value
26
+
27
+ while meaning to type:
28
+
29
+ do_something if value || other_value
30
+
31
+ and value is a Symbol, instead of a NoMethodError being raised because Symbol#| is not implemented by default, <tt>value | other_value</tt> will return a Sequel expression object, which if will evaluate as true, and do_something will be called.
32
+
33
+ == Usage
34
+
35
+ All of Sequel's extensions to the core classes are stored in Sequel's core_extensions extension, which you can load via:
36
+
37
+ Sequel.extension :core_extensions
38
+
39
+ For backwards compatibility, the core_extensions are loaded by default in Sequel 3. Starting in Sequel 4, the core extensions will no longer be loaded by default, so you will have to load the core_extensions extension manually using the above code. If you plan to use the core extensions, it's recommended that you manually load the extension, even in Sequel 3. If you do not plan to use the core extensions, you can change from:
40
+
41
+ require 'sequel'
42
+
43
+ to:
44
+
45
+ require 'sequel/no_core_ext'
46
+
47
+ which will load Sequel without the core extensions.
48
+
49
+ == No Internal Dependency
50
+
51
+ Sequel has no internal dependency on the core extensions. This includes Sequel's core, Sequel::Model, and all plugins and extensions that ship with Sequel. However, it is possible that external plugins and extensions will depend on the core extensions. Such plugins and extensions should be updated so that they no longer depend on the core extensions.
52
+
53
+ == Core Extension Methods
54
+
55
+ This section will briefly describe all of the methods added to the core classes, and what the alternative method is that doesn't require the core extensions.
56
+
57
+ === Symbol & String
58
+
59
+ ==== as
60
+
61
+ Symbol#as and String#as return Sequel aliased expressions using the provided alias:
62
+
63
+ :a.as(:b) # SQL: a AS b
64
+ 'a'.as(:b) # SQL: 'a' AS b
65
+
66
+ Alternative: Sequel.as:
67
+
68
+ Sequel.as(:a, :b)
69
+
70
+ ==== cast
71
+
72
+ Symbol#cast and String#cast return Sequel cast expressions for typecasting in the database:
73
+
74
+ :a.cast(Integer) # SQL: CAST(a AS integer)
75
+ 'a'.cast(Integer) # SQL: CAST('a' AS integer)
76
+
77
+ Alternative: Sequel.cast:
78
+
79
+ Sequel.cast(:a, Integer)
80
+
81
+ ==== cast_numeric
82
+
83
+ Symbol#cast_numeric and String#cast_numeric return Sequel cast expressions for typecasting in the database, defaulting to integers, where the returned expression is treated as an numeric value:
84
+
85
+ :a.cast_numeric # SQL: CAST(a AS integer)
86
+ 'a'.cast_numeric(Float) # SQL: CAST('a' AS double precision)
87
+
88
+ Alternative: Sequel.cast_numeric:
89
+
90
+ Sequel.cast_numeric(:a)
91
+
92
+ ==== cast_string
93
+
94
+ Symbol#cast_string and String#cast_string return Sequel cast expressions for typecasting in the database, defaulting to strings, where the returned expression is treated as a string value:
95
+
96
+ :a.cast_string # SQL: CAST(a AS varchar(255))
97
+ 'a'.cast_string(:text) # SQL: CAST('a' AS text)
98
+
99
+ Alternative: Sequel.cast_string:
100
+
101
+ Sequel.cast_string(:a)
102
+
103
+ === Symbol
104
+
105
+ ==== identifier
106
+
107
+ Symbol#identifier wraps the symbol in a single identifier that will not be split. By default, Sequel will split symbols with double or triple underscores to do qualifying and aliasing.
108
+
109
+ :table__column.identifier # SQL: table__column
110
+
111
+ Alternative: Sequel.identifier:
112
+
113
+ Sequel.identifier(:table__column)
114
+
115
+ ==== asc
116
+
117
+ Symbol#asc is used to define an ascending order on a column. It exists mostly for consistency with #desc, since ascending is the default order:
118
+
119
+ :a.asc # SQL: a ASC
120
+
121
+ Alternative: Sequel.asc:
122
+
123
+ Sequel.asc(:a)
124
+
125
+ ==== desc
126
+
127
+ Symbol#desc is used to defined a descending order on a column. The returned value is usually passed to one of the dataset order methods.
128
+
129
+ :a.desc # SQL: a DESC
130
+
131
+ Alternative: Sequel.desc:
132
+
133
+ Sequel.desc(:a)
134
+
135
+ ==== +, -, *, /
136
+
137
+ The standard mathematical operators are defined on Symbol, and return a Sequel numeric expression object representing the operation:
138
+
139
+ :a + :b # SQL: a + b
140
+ :a - :b # SQL: a - b
141
+ :a * :b # SQL: a * b
142
+ :a / :b # SQL: a / b
143
+
144
+ Alternatives:
145
+
146
+ Sequel.+(:a, :b)
147
+ Sequel.-(:a, :b)
148
+ Sequel.*(:a, :b)
149
+ Sequel./(:a, :b)
150
+
151
+ ==== *
152
+
153
+ The * operator is overloaded on Symbol such that if it is called with no arguments, it represents a selection of all columns in the table:
154
+
155
+ :a.* # SQL: a.*
156
+
157
+ Alternative: Sequel.expr.*:
158
+
159
+ Sequel.expr(:a).*
160
+
161
+ ==== qualify
162
+
163
+ Symbol#qualify qualifies the identifier (e.g. a column) with a another identifier (e.g. a table):
164
+
165
+ :column.qualify(:table) # SQL: table.column
166
+
167
+ Alternative: Sequel.qualify:
168
+
169
+ Sequel.qualify(:table, :column)
170
+
171
+ Note the reversed order of the arguments. For the Symbol#qualify method, the argument is the qualifier, while for Sequel.qualify, the qualifier is the first argument.
172
+
173
+ ==== like
174
+
175
+ Symbol#like returns a case sensitive LIKE expression between the identifier and the given argument:
176
+
177
+ :a.like('b%') # SQL: a LIKE 'b%'
178
+
179
+ Alternative: Sequel.like:
180
+
181
+ Sequel.like(:a, 'b%')
182
+
183
+ ==== like
184
+
185
+ Symbol#ilike returns a case insensitive LIKE expression between the identifier and the given argument:
186
+
187
+ :a.ilike('b%') # SQL: a ILIKE 'b%'
188
+
189
+ Alternative: Sequel.ilike:
190
+
191
+ Sequel.ilike(:a, 'b%')
192
+
193
+ ==== sql_subscript
194
+
195
+ Symbol#sql_subscript returns a Sequel expression representing an SQL array access:
196
+
197
+ :a.sql_subscript(1) # SQL: a[1]
198
+
199
+ Alternative: Sequel.subscript:
200
+
201
+ Sequel.subscript(:a, 1)
202
+
203
+ ==== extract
204
+
205
+ Symbol#extract does a datetime part extraction from the receiver:
206
+
207
+ :a.extract(:year) # SQL: extract(year FROM a)
208
+
209
+ Alternative: Sequel.extract:
210
+
211
+ Sequel.extract(:year, :a)
212
+
213
+ Note the reversed order of the arguments. In Symbol#extract, the datetime part is the argument, while in Sequel.extract, the datetime part is the first argument.
214
+
215
+ ==== sql_boolean, sql_number, sql_string
216
+
217
+ These Symbol methods are used to force the treating of the object as a specific SQL type, instead of as a general SQL type. For example:
218
+
219
+ :a.sql_boolean + 1 # NoMethodError
220
+ :a.sql_number << 1 # SQL: a << 1
221
+ :a.sql_string + 'a' # SQL: a || 'a'
222
+
223
+ Alternative: Sequel.expr:
224
+
225
+ Sequel.expr(:a).sql_boolean
226
+ Sequel.expr(:a).sql_number
227
+ Sequel.expr(:a).sql_string
228
+
229
+ ==== sql_function
230
+
231
+ Symbol#sql_function returns an SQL function call expression object:
232
+
233
+ :now.sql_function # SQL: now()
234
+ :sum.sql_function(:a) # SQL: sum(a)
235
+ :concat.sql_function(:a, :b) # SQL: concat(a, b)
236
+
237
+ Alternative: Sequel.function:
238
+
239
+ Sequel.function(:now, :a)
240
+
241
+ === String
242
+
243
+ ==== lit
244
+
245
+ String#lit creates a literal string, using placeholders if any arguments are given. Literal strings are not escaped, they are treated as SQL code, not as an SQL string:
246
+
247
+ 'a'.lit # SQL: a
248
+ '"a" = ?'.lit(1) # SQL: "a" = 1
249
+
250
+ Alternative: Sequel.lit:
251
+
252
+ Sequel.lit('a')
253
+
254
+ ==== to_sequel_blob
255
+
256
+ String#to_sequel_blob returns the string wrapper in Sequel blob object. Often blobs need to be handled differently than regular strings by the database adapters.
257
+
258
+ "a\0".to_sequel_blob # SQL: X'6100'
259
+
260
+ Alternative: Sequel.blob:
261
+
262
+ Sequel.blob("a\0")
263
+
264
+ === Hash, Array, & Symbol
265
+
266
+ ==== ~
267
+
268
+ Array#~, Hash#~, and Symbol#~ treat the receiver as a conditions specifier, not matching all of the conditions:
269
+
270
+ ~{:a=>1, :b=>[2, 3]} # SQL: a != 1 OR b NOT IN (2, 3)
271
+ ~[[:a, 1], [:b, [1, 2]]] # SQL: a != 1 OR b NOT IN (1, 2)
272
+
273
+ Alternative: Sequel.~:
274
+
275
+ Sequel.~(:a=>1, :b=>[2, 3])
276
+
277
+ === Hash & Array
278
+
279
+ ==== case
280
+
281
+ Array#case and Hash#case return an SQL CASE expression, where the keys are conditions and the values are results:
282
+
283
+ {{:a=>[2,3]}=>1}.case(0) # SQL: CASE WHEN a IN (2, 3) THEN 1 ELSE 0 END
284
+ [[{:a=>[2,3]}, 1]].case(0) # SQL: CASE WHEN a IN (2, 3) THEN 1 ELSE 0 END
285
+
286
+ Alternative: Sequel.case:
287
+
288
+ Sequel.case({:a=>[2,3]}=>1}, 0)
289
+
290
+ ==== sql_expr
291
+
292
+ Array#sql_expr and Hash#sql_expr treat the receiver as a conditions specifier, matching all of the conditions in the array.
293
+
294
+ {:a=>1, :b=>[2, 3]}.sql_expr # SQL: a = 1 AND b IN (2, 3)
295
+ [[:a, 1], [:b, [2, 3]]].sql_expr # SQL: a = 1 AND b IN (2, 3)
296
+
297
+ Alternative: Sequel.expr:
298
+
299
+ Sequel.expr(:a=>1, :b=>[2, 3])
300
+
301
+ ==== sql_negate
302
+
303
+ Array#sql_negate and Hash#sql_negate treat the receiver as a conditions specifier, matching none of the conditions in the array:
304
+
305
+ {:a=>1, :b=>[2, 3]}.sql_negate # SQL: a != 1 AND b NOT IN (2, 3)
306
+ [[:a, 1], [:b, [2, 3]]].sql_negate # SQL: a != 1 AND b NOT IN (2, 3)
307
+
308
+ Alternative: Sequel.negate:
309
+
310
+ Sequel.negate(:a=>1, :b=>[2, 3])
311
+
312
+ ==== sql_or
313
+
314
+ Array#sql_or nd Hash#sql_or treat the receiver as a conditions specifier, matching any of the conditions in the array:
315
+
316
+ {:a=>1, :b=>[2, 3]}.sql_or # SQL: a = 1 OR b IN (2, 3)
317
+ [[:a, 1], [:b, [2, 3]]].sql_or # SQL: a = 1 OR b IN (2, 3)
318
+
319
+ Alternative: Sequel.or:
320
+
321
+ Sequel.or(:a=>1, :b=>[2, 3])
322
+
323
+ === Array
324
+
325
+ ==== sql_value_list
326
+
327
+ Array#sql_value_list wraps the array in an array subclass, which Sequel will always treat as a value list and not a conditions specifier. By default, Sequel treats arrays of two element arrays as a conditions specifier.
328
+
329
+ DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]]) # SQL: (a, b) IN ((1 = 2) AND (3 = 4))
330
+ DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]].sql_value_list) # SQL: (a, b) IN ((1, 2), (3, 4))
331
+
332
+ Alternative: Sequel.value_list:
333
+
334
+ Sequel.value_list([[1, 2], [3, 4]])
335
+
336
+ ==== sql_string_join
337
+
338
+ Array#sql_string_join joins all of the elements in the array in an SQL string concatentation expression:
339
+
340
+ [:a].sql_string_join # SQL: a
341
+ [:a, :b].sql_string_join # SQL: a || b
342
+ [:a, 'b'].sql_string_join # SQL: a || 'b'
343
+ ['a', :b].sql_string_join(' ') # SQL: 'a' || ' ' || b
344
+
345
+ Alternative: Sequel.join:
346
+
347
+ Sequel.join(['a', :b], ' ')
348
+
349
+ === Hash & Symbol
350
+
351
+ ==== &
352
+
353
+ Hash#& and Symbol#& return a Sequel boolean expression, matching the condition specified by the receiver and the condition specified by the given argument:
354
+
355
+ :a & :b # SQL: a AND b
356
+ {:a=>1} & :b # SQL: a = 1 AND b
357
+ {:a=>true} & :b # SQL: a IS TRUE AND b
358
+
359
+ Alternative: Sequel.&:
360
+
361
+ Sequel.&({:a=>1}, :b)
362
+
363
+ ==== |
364
+
365
+ Hash#| returns a Sequel boolean expression, matching the condition specified by the receiver or the condition specified by the given argument:
366
+
367
+ :a | :b # SQL: a OR b
368
+ {:a=>1} | :b # SQL: a = 1 OR b
369
+ {:a=>true} | :b # SQL: a IS TRUE OR b
370
+
371
+ Alternative: Sequel.|:
372
+
373
+ Sequel.|({:a=>1}, :b)
374
+