sequel 5.12.0 → 5.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d316ca35fb36d4b3777021b4e3d6c108036f0bb1197ab7c9efc4529012858d1
4
- data.tar.gz: 7f0e338f35027945f84cfeb9d6d997114e098f46d74b7b2fc3e32db34c4f5925
3
+ metadata.gz: bc4068290931cd51d12ec42e40a1e383ffa9cc8448501970230ec0863fc1cc21
4
+ data.tar.gz: 16c549d0adcd8700bfb498bc2a459437a37c57a85d9048099336105efff376ad
5
5
  SHA512:
6
- metadata.gz: 8d5f3c64cf5e6361ced90c90c0cfd8e3f35cfb50e2e5acfd7b25b79728dbf207bf673e03662ab72e9208cd283675e278f126d27d656a7e2f7ec0baec7330a0b4
7
- data.tar.gz: c741e9fd139c5e8b13c0c434f66836bbecba900f03eecddf559f1992d4155bfcb2af1e846425d9f495fc442f09e79c82e1933dc3a362f81caced379ef608e248
6
+ metadata.gz: 3f6acb6af9670774bf87b19349e778cb7b967ac529bbd192ea3ce2b6790080c21afa4445faabe18de148cfcef894e5457924782fb5462289dc38ff9af4ab5fcb
7
+ data.tar.gz: e03cf594244024d41de805ef57bcdc545bd9bb247e34fcd48e1d6fba8c558f8dacc49828b5f529e465b9a5a6089e66adc5e1a8d43cf7029225556429aa97441b
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ === 5.13.0 (2018-10-01)
2
+
3
+ * Support :single_value type in prepared statements (rintaun) (#1547)
4
+
5
+ * Make Model.all in static_cache plugin accept a block (AlexWayfer, jeremyevans) (#1543)
6
+
7
+ * Add constant_sql_override extension for overriding SQL used for constants such as CURRENT_TIMESTAMP (celsworth) (#1538)
8
+
9
+ * Do not cache from_self datasets if options are given (jeremyevans)
10
+
1
11
  === 5.12.0 (2018-08-31)
2
12
 
3
13
  * Make constraint_validations extension respect Database#constraint_validations_table setting (jeremyevans)
data/README.rdoc CHANGED
@@ -9,7 +9,7 @@ toolkit for Ruby.
9
9
  records to Ruby objects and handling associated records.
10
10
  * Sequel supports advanced database features such as prepared
11
11
  statements, bound variables, savepoints, two-phase commit,
12
- transaction isolation, master/slave configurations, and
12
+ transaction isolation, primary/replica configurations, and
13
13
  database sharding.
14
14
  * Sequel currently has adapters for ADO, Amalgalite,
15
15
  IBM_DB, JDBC, MySQL, Mysql2, ODBC, Oracle,
@@ -15,13 +15,13 @@ and you call a mass assignment method with a hash:
15
15
 
16
16
  the mass assignment method will go through each key in the hash, append <tt>=</tt> to it to determine the
17
17
  setter method, and if the setter method is defined and access to it is not restricted, Sequel will call the
18
- setter method with the hash value. So if we assume that the posts table has subject and text columns, what
18
+ setter method with the hash value. So if we assume that the posts table has title and body columns, what
19
19
  the above mass assignment call actually does is:
20
-
20
+
21
21
  post.title=('T')
22
22
  post.body=('B')
23
23
 
24
- By default, there are two types of setter methods that are restricted.
24
+ By default, there are two types of setter methods that are restricted.
25
25
  The first is methods like <tt>typecast_on_assignment=</tt> and <tt>==</tt>, which don't affect columns.
26
26
  These methods cannot be enabled for mass assignment.
27
27
  The second is primary key setters.
@@ -83,7 +83,7 @@ These options are shared by all adapters unless otherwise noted.
83
83
  :log_connection_info :: Whether to include connection information in log messages (false by default)
84
84
  :log_warn_duration :: The amount of seconds after which the queries are logged at :warn level
85
85
  :password :: The password for the user account
86
- :servers :: A hash with symbol keys and hash or proc values, used with master/slave/partitioned database configurations
86
+ :servers :: A hash with symbol keys and hash or proc values, used with primary/replica and sharded database configurations
87
87
  :sql_log_level :: The level at which to issue queries to the loggers (:info by default)
88
88
  :test :: Whether to test that a valid database connection can be made (true by default)
89
89
  :user :: The user account name to use logging in
@@ -0,0 +1,27 @@
1
+ = New Features
2
+
3
+ * A constant_sql_override Database extension has been added, allowing
4
+ for overriding the SQL used by constants such as
5
+ Sequel::CURRENT_TIMESTAMP. This can be used to force
6
+ CURRENT_TIMESTAMP to be literalized at a particular time zone:
7
+
8
+ DB.extension :constant_sql_override
9
+ DB.set_constant_sql(Sequel::CURRENT_TIMESTAMP,
10
+ "CURRENT_TIMESTAMP AT TIME ZONE 'UTC'")
11
+
12
+ * Prepared statements now support the :single_value type, which
13
+ returns the first column value in the dataset.
14
+
15
+ prep_stmt = DB[:table].select(:column).prepare(:single_value, :ps)
16
+ prep_stmt.call
17
+ # PREPARE ps AS SELECT column FROM table LIMIT 1;
18
+ # EXECUTE ps;
19
+ # => 42
20
+
21
+ = Other Improvements
22
+
23
+ * Dataset#from_self will no longer use a cached dataset if any options
24
+ are given, as that can result in incorrect behavior.
25
+
26
+ * Model.all in the static_cache plugin now accepts a block, mirroring
27
+ the API when the static_cache plugin is not used.
data/doc/sharding.rdoc CHANGED
@@ -1,7 +1,7 @@
1
- = Read-Only Slaves/Writable Master and Database Sharding
1
+ = Primary/Replica Configurations and Database Sharding
2
2
 
3
- Sequel has support for read only slave databases
4
- with a writable master database, as well as database sharding (where you can
3
+ Sequel has support for primary/replica configurations (writable primary
4
+ database with read only replicas databases), as well as database sharding (where you can
5
5
  pick a server to use for a given dataset). Support for both
6
6
  features is database independent, and should work for all database adapters
7
7
  that ship with Sequel.
@@ -13,7 +13,7 @@ option. Using the :servers database option makes Sequel use a connection pool
13
13
  class that supports sharding, and the minimum required to enable sharding
14
14
  support is to use the empty hash:
15
15
 
16
- DB=Sequel.connect('postgres://master_server/database', servers: {})
16
+ DB=Sequel.connect('postgres://primary_server/database', servers: {})
17
17
 
18
18
  In most cases, you are probably not going to want to use an empty hash. Keys in the server hash are
19
19
  not restricted to type, but the general recommendation is to use a symbol
@@ -28,69 +28,69 @@ a :host entry in each shard's hash.
28
28
  Note that all servers should have the same schema for all
29
29
  tables you are accessing, unless you really know what you are doing.
30
30
 
31
- == Master and Slave Database Configurations
31
+ == Primary and Replica Database Configurations
32
32
 
33
- === Single Read-Only Slave, Single Master
33
+ === Single Primary, Single Replica
34
34
 
35
- To use a single, read-only slave that handles SELECT queries, the following
35
+ To use a single, read-only replica that handles SELECT queries, the following
36
36
  is the simplest configuration:
37
37
 
38
- DB=Sequel.connect('postgres://master_server/database',
39
- servers: {read_only: {host: 'slave_server'}})
38
+ DB=Sequel.connect('postgres://primary_server/database',
39
+ servers: {read_only: {host: 'replica_server'}})
40
40
 
41
- This will use the slave_server for SELECT queries and master_server for
41
+ This will use the replica_server for SELECT queries and primary_server for
42
42
  other queries.
43
43
 
44
44
  If you want to ensure your queries are going to a specific database, you
45
45
  can force this for a given query by using the .server method and passing
46
46
  the symbol name defined in the connect options. For example:
47
47
 
48
- # Force the SELECT to run on the master
48
+ # Force the SELECT to run on the primary server
49
49
  DB[:users].server(:default).all
50
50
 
51
- # Force the DELETE to run on the read-only slave
51
+ # Force the DELETE to run on the read-only replica
52
52
  DB[:users].server(:read_only).delete
53
53
 
54
- === Multiple Read-Only Slaves, Single Master
54
+ === Single Primary, Multiple Replicas
55
55
 
56
- Let's say you have 4 slave database servers with names slave_server0,
57
- slave_server1, slave_server2, and slave_server3.
56
+ Let's say you have 4 replica servers with names replica_server0,
57
+ replica_server1, replica_server2, and replica_server3.
58
58
 
59
59
  num_read_only = 4
60
60
  read_only_host = rand(num_read_only)
61
61
  read_only_proc = proc do |db|
62
- {host: "slave_server#{(read_only_host+=1) % num_read_only}"}
62
+ {host: "replica_server#{(read_only_host+=1) % num_read_only}"}
63
63
  end
64
- DB=Sequel.connect('postgres://master_server/database',
64
+ DB=Sequel.connect('postgres://primary_server/database',
65
65
  servers: {read_only: read_only_proc})
66
66
 
67
- This will use one of the slave servers for SELECT queries and use the
68
- master server for other queries. It's also possible to pick a random host
67
+ This will use one of the replica servers for SELECT queries and use the
68
+ primary server for other queries. It's also possible to pick a random host
69
69
  instead of using the round robin approach presented above, but that can result
70
70
  in less optimal resource usage.
71
71
 
72
- === Multiple Read-Only Slaves, Multiple Masters
72
+ === Multiple Primary, Multiple Replicas
73
73
 
74
- This involves the same basic idea as the multiple slaves, single master, but
75
- it shows that the master database is named :default. So for 4 masters and
76
- 4 slaves:
74
+ This involves the same basic idea as the multiple replicas, single primary, but
75
+ it shows that the primary database is named :default. So for 4 primary servers and
76
+ 4 replica servers:
77
77
 
78
78
  num_read_only = 4
79
79
  read_only_host = rand(num_read_only)
80
80
  read_only_proc = proc do |db|
81
- {host: "slave_server#{(read_only_host+=1) % num_read_only}"}
81
+ {host: "replica_server#{(read_only_host+=1) % num_read_only}"}
82
82
  end
83
83
  num_default = 4
84
84
  default_host = rand(num_default)
85
85
  default_proc = proc do |db|
86
- {host: "master_server#{(default_host+=1) % num_default}"}
86
+ {host: "primary_server#{(default_host+=1) % num_default}"}
87
87
  end
88
- DB=Sequel.connect('postgres://master_server/database',
88
+ DB=Sequel.connect('postgres://primary_server/database',
89
89
  servers: {default: default_proc, read_only: read_only_proc})
90
90
 
91
91
  == Sharding
92
92
 
93
- There is specific support in Sequel for handling master/slave database
93
+ There is specific support in Sequel for handling primary/replica database
94
94
  combinations, with the only necessary setup being the database configuration.
95
95
  However, since sharding is always going to be implementation dependent, Sequel
96
96
  supplies the basic infrastructure, but you have to tell it which server to use
@@ -210,7 +210,7 @@ need to do that, call the server method explicitly on the dataset used to retrie
210
210
  model objects.
211
211
 
212
212
  The with_server method also supports a second argument for the default read_only server
213
- to use, which can be useful if you are mixing sharding and master/slave servers:
213
+ to use, which can be useful if you are mixing sharding and primary/replica servers:
214
214
 
215
215
  DB.extension :server_block
216
216
  DB.with_server(:a, :a_read_only) do
@@ -253,8 +253,8 @@ module Sequel
253
253
  recordset.GetRows.transpose.each do |field_values|
254
254
  h = {}
255
255
 
256
- cols.each do |name, cp, i|
257
- h[name] = if (v = field_values[i]) && cp
256
+ cols.each do |name, cp, index|
257
+ h[name] = if (v = field_values[index]) && cp
258
258
  cp[v]
259
259
  else
260
260
  v
@@ -19,9 +19,9 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
19
19
  add_servers(opts[:servers].keys) if opts[:servers]
20
20
  end
21
21
 
22
- # Adds new servers to the connection pool. Primarily used in conjunction with master/slave
23
- # or shard configurations. Allows for dynamic expansion of the potential slaves/shards
24
- # at runtime. servers argument should be an array of symbols.
22
+ # Adds new servers to the connection pool. Primarily used in conjunction with primary/replica
23
+ # or sharded configurations. Allows for dynamic expansion of the potential replicas/shards
24
+ # at runtime. +servers+ argument should be an array of symbols.
25
25
  def add_servers(servers)
26
26
  servers.each{|s| @servers[s] = s}
27
27
  end
@@ -28,8 +28,8 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
28
28
  add_servers(opts[:servers].keys) if opts[:servers]
29
29
  end
30
30
 
31
- # Adds new servers to the connection pool. Allows for dynamic expansion of the potential slaves/shards
32
- # at runtime. servers argument should be an array of symbols.
31
+ # Adds new servers to the connection pool. Allows for dynamic expansion of the potential replicas/shards
32
+ # at runtime. +servers+ argument should be an array of symbols.
33
33
  def add_servers(servers)
34
34
  sync do
35
35
  servers.each do |server|
data/lib/sequel/core.rb CHANGED
@@ -116,7 +116,7 @@ module Sequel
116
116
  # terminates, or use the <tt>keep_reference: false</tt> Database option.
117
117
  #
118
118
  # For details, see the {"Connecting to a Database" guide}[rdoc-ref:doc/opening_databases.rdoc].
119
- # To set up a master/slave or sharded database connection, see the {"Master/Slave Databases and Sharding" guide}[rdoc-ref:doc/sharding.rdoc].
119
+ # To set up a primary/replica or sharded database connection, see the {"Primary/Replica Database Configurations and Sharding" guide}[rdoc-ref:doc/sharding.rdoc].
120
120
  def self.connect(*args, &block)
121
121
  Database.connect(*args, &block)
122
122
  end
@@ -281,7 +281,7 @@ module Sequel
281
281
  end
282
282
 
283
283
  # Whether this database instance uses multiple servers, either for sharding
284
- # or for master/slave.
284
+ # or for primary/replica configurations.
285
285
  def sharded?
286
286
  @sharded
287
287
  end
@@ -81,7 +81,8 @@ module Sequel
81
81
  constraint(nil, *args, &block)
82
82
  end
83
83
 
84
- # Add a column with the given name, type, and opts #
84
+ # Add a column with the given name, type, and opts:
85
+ #
85
86
  # column :num, :integer
86
87
  # # num INTEGER
87
88
  #
@@ -158,7 +159,7 @@ module Sequel
158
159
  nil
159
160
  end
160
161
 
161
- # Add a foreign key in the table that references another table. See column
162
+ # Add a foreign key in the table that references another table. See #column
162
163
  # for available options.
163
164
  #
164
165
  # foreign_key(:artist_id) # artist_id INTEGER
@@ -241,7 +242,7 @@ module Sequel
241
242
  nil
242
243
  end
243
244
 
244
- # Add a column with the given type, name, and opts. See +column+ for available
245
+ # Add a column with the given type, name, and opts. See #column for available
245
246
  # options.
246
247
  def method_missing(type, name = nil, opts = OPTS)
247
248
  name ? column(name, type, opts) : super
@@ -91,7 +91,7 @@ module Sequel
91
91
  end
92
92
 
93
93
  # The type of prepared statement, should be one of :select, :first,
94
- # :insert, :update, or :delete
94
+ # :insert, :update, :delete, or :single_value
95
95
  def prepared_type
96
96
  @opts[:prepared_type]
97
97
  end
@@ -144,7 +144,7 @@ module Sequel
144
144
  when :select, :all, :each
145
145
  # Most common scenario, so listed first.
146
146
  select_sql
147
- when :first
147
+ when :first, :single_value
148
148
  clone(:limit=>1).select_sql
149
149
  when :insert_select
150
150
  insert_select_sql(*prepared_modify_values)
@@ -205,6 +205,8 @@ module Sequel
205
205
  when :map, :as_hash, :to_hash, :to_hash_groups
206
206
  public_send(*prepared_type, &block)
207
207
  end
208
+ when :single_value
209
+ single_value
208
210
  else
209
211
  raise Error, "unsupported prepared statement type used: #{prepared_type.inspect}"
210
212
  end
@@ -290,7 +292,7 @@ module Sequel
290
292
  ds = ds.clone(:recorder=>pl)
291
293
 
292
294
  case type
293
- when :first
295
+ when :first, :single_value
294
296
  ds.limit(1)
295
297
  when :update, :insert, :insert_select, :delete
296
298
  ds.with_sql(:"#{type}_sql", *values)
@@ -339,7 +341,7 @@ module Sequel
339
341
  clone(:bind_vars=>bind_vars)
340
342
  end
341
343
 
342
- # For the given type (:select, :first, :insert, :insert_select, :update, or :delete),
344
+ # For the given type (:select, :first, :insert, :insert_select, :update, :delete, or :single_value),
343
345
  # run the sql with the bind variables specified in the hash. +values+ is a hash passed to
344
346
  # insert or update (if one of those types is used), which may contain placeholders.
345
347
  #
@@ -291,7 +291,7 @@ module Sequel
291
291
  c
292
292
  end
293
293
 
294
- cache ? cached_dataset(:_from_self_ds, &pr) : pr.call
294
+ opts.empty? ? cached_dataset(:_from_self_ds, &pr) : pr.call
295
295
  end
296
296
 
297
297
  # Match any of the columns to any of the patterns. The terms can be
@@ -0,0 +1,65 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The constant_sql_override extension allows you to change the SQL
4
+ # generated for Sequel constants.
5
+ #
6
+ # One possible use-case for this is to have Sequel::CURRENT_TIMESTAMP use UTC time when
7
+ # you have Sequel.database_timezone = :utc, but the database uses localtime when
8
+ # generating CURRENT_TIMESTAMP.
9
+ #
10
+ # You can set SQL overrides with Database#set_constant_sql:
11
+ #
12
+ # DB.set_constant_sql(Sequel::CURRENT_TIMESTAMP, "CURRENT_TIMESTAMP AT TIME ZONE 'UTC'")
13
+ #
14
+ # Now, using Sequel::CURRENT_TIMESTAMP will use your override instead:
15
+ #
16
+ # Album.where(released_at: Sequel::CURRENT_TIMESTAMP).sql
17
+ # # => SELECT "albums.*" FROM "albums" WHERE ("released_at" = CURRENT_TIMESTAMP AT TIME ZONE 'UTC')
18
+ #
19
+ # To use this extension, first load it into your Sequel::Database instance:
20
+ #
21
+ # DB.extension :constant_sql_override
22
+ #
23
+ # Related module: Sequel::ConstantSqlOverride
24
+
25
+ #
26
+ module Sequel
27
+ module ConstantSqlOverride
28
+ module DatabaseMethods
29
+ # Create the initial empty hash of constant sql overrides.
30
+ def self.extended(db)
31
+ db.instance_exec do
32
+ @constant_sqls ||= {}
33
+ extend_datasets(DatasetMethods)
34
+ end
35
+ end
36
+
37
+ # Hash mapping constant symbols to SQL. For internal use only.
38
+ attr_reader :constant_sqls # :nodoc:
39
+
40
+ # Set the SQL to use for the given Sequel::SQL::Constant
41
+ def set_constant_sql(constant, override)
42
+ @constant_sqls[constant.constant] = override
43
+ end
44
+
45
+ # Freeze the constant_sqls hash to prevent adding new overrides.
46
+ def freeze
47
+ @constant_sqls.freeze
48
+ super
49
+ end
50
+ end
51
+
52
+ module DatasetMethods
53
+ # Use overridden constant SQL
54
+ def constant_sql_append(sql, constant)
55
+ if constant_sql = db.constant_sqls[constant]
56
+ sql << constant_sql
57
+ else
58
+ super
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ Database.register_extension(:constant_sql_override, ConstantSqlOverride::DatabaseMethods)
65
+ end
@@ -2641,7 +2641,7 @@ module Sequel
2641
2641
  # Album.eager(:artist, :genre).all
2642
2642
  # Album.eager_graph(:artist, :genre).all
2643
2643
  # Album.eager(:artist).eager(:genre).all
2644
- # Album.eager_graph(:artist).eager(:genre).all
2644
+ # Album.eager_graph(:artist).eager_graph(:genre).all
2645
2645
  # Artist.eager(albums: :tracks).all
2646
2646
  # Artist.eager_graph(albums: :tracks).all
2647
2647
  # Artist.eager(albums: {tracks: :genre}).all
@@ -2674,13 +2674,79 @@ module Sequel
2674
2674
  end
2675
2675
 
2676
2676
  # Adds one or more INNER JOINs to the existing dataset using the keys and conditions
2677
- # specified by the given association. The following methods also exist for specifying
2678
- # a different type of JOIN:
2677
+ # specified by the given association(s). Take the same arguments as eager_graph, and
2678
+ # operates similarly, but only adds the joins as opposed to making the other changes
2679
+ # (such as adding selected columns and setting up eager loading).
2680
+ #
2681
+ # The following methods also exist for specifying a different type of JOIN:
2679
2682
  #
2680
2683
  # association_full_join :: FULL JOIN
2681
2684
  # association_inner_join :: INNER JOIN
2682
2685
  # association_left_join :: LEFT JOIN
2683
2686
  # association_right_join :: RIGHT JOIN
2687
+ #
2688
+ # Examples:
2689
+ #
2690
+ # # For each album, association_join load the artist
2691
+ # Album.association_join(:artist).all
2692
+ # # SELECT *
2693
+ # # FROM albums
2694
+ # # INNER JOIN artists AS artist ON (artists.id = albums.artist_id)
2695
+ #
2696
+ # # For each album, association_join load the artist, using a specified alias
2697
+ # Album.association_join(Sequel[:artist].as(:a)).all
2698
+ # # SELECT *
2699
+ # # FROM albums
2700
+ # # INNER JOIN artists AS a ON (a.id = albums.artist_id)
2701
+ #
2702
+ # # For each album, association_join load the artist and genre
2703
+ # Album.association_join(:artist, :genre).all
2704
+ # Album.association_join(:artist).association_join(:genre).all
2705
+ # # SELECT *
2706
+ # # FROM albums
2707
+ # # INNER JOIN artists AS artist ON (artist.id = albums.artist_id)
2708
+ # # INNER JOIN genres AS genre ON (genre.id = albums.genre_id)
2709
+ #
2710
+ # # For each artist, association_join load albums and tracks for each album
2711
+ # Artist.association_join(albums: :tracks).all
2712
+ # # SELECT *
2713
+ # # FROM artists
2714
+ # # INNER JOIN albums ON (albums.artist_id = artists.id)
2715
+ # # INNER JOIN tracks ON (tracks.album_id = albums.id)
2716
+ #
2717
+ # # For each artist, association_join load albums, tracks for each album, and genre for each track
2718
+ # Artist.association_join(albums: {tracks: :genre}).all
2719
+ # # SELECT *
2720
+ # # FROM artists
2721
+ # # INNER JOIN albums ON (albums.artist_id = artists.id)
2722
+ # # INNER JOIN tracks ON (tracks.album_id = albums.id)
2723
+ # # INNER JOIN genres AS genre ON (genre.id = tracks.genre_id)
2724
+ #
2725
+ # # For each artist, association_join load albums with year > 1990
2726
+ # Artist.association_join(albums: proc{|ds| ds.where{year > 1990}}).all
2727
+ # # SELECT *
2728
+ # # FROM artists
2729
+ # # INNER JOIN (
2730
+ # # SELECT * FROM albums WHERE (year > 1990)
2731
+ # # ) AS albums ON (albums.artist_id = artists.id)
2732
+ #
2733
+ # # For each artist, association_join load albums and tracks 1-10 for each album
2734
+ # Artist.association_join(albums: {tracks: proc{|ds| ds.where(number: 1..10)}}).all
2735
+ # # SELECT *
2736
+ # # FROM artists
2737
+ # # INNER JOIN albums ON (albums.artist_id = artists.id)
2738
+ # # INNER JOIN (
2739
+ # # SELECT * FROM tracks WHERE ((number >= 1) AND (number <= 10))
2740
+ # # ) AS tracks ON (tracks.albums_id = albums.id)
2741
+ #
2742
+ # # For each artist, association_join load albums with year > 1990, and tracks for those albums
2743
+ # Artist.association_join(albums: {proc{|ds| ds.where{year > 1990}}=>:tracks}).all
2744
+ # # SELECT *
2745
+ # # FROM artists
2746
+ # # INNER JOIN (
2747
+ # # SELECT * FROM albums WHERE (year > 1990)
2748
+ # # ) AS albums ON (albums.artist_id = artists.id)
2749
+ # # INNER JOIN tracks ON (tracks.album_id = albums.id)
2684
2750
  def association_join(*associations)
2685
2751
  association_inner_join(*associations)
2686
2752
  end
@@ -2760,6 +2826,56 @@ module Sequel
2760
2826
  #
2761
2827
  # Each association's order, if defined, is respected.
2762
2828
  # If the association uses a block or has an :eager_block argument, it is used.
2829
+ #
2830
+ # To modify the associated dataset that will be used for the eager load, you should use a
2831
+ # hash for the association, with the key being the association name symbol, and the value being
2832
+ # a callable object that is called with the associated dataset and should return a modified
2833
+ # dataset. If that association also has dependent associations, instead of a callable object,
2834
+ # use a hash with the callable object being the key, and the dependent association(s) as the value.
2835
+ #
2836
+ # Examples:
2837
+ #
2838
+ # # For each album, eager load the artist
2839
+ # Album.eager(:artist).all
2840
+ # # SELECT * FROM albums
2841
+ # # SELECT * FROM artists WHERE (id IN (...))
2842
+ #
2843
+ # # For each album, eager load the artist and genre
2844
+ # Album.eager(:artist, :genre).all
2845
+ # Album.eager(:artist).eager(:genre).all
2846
+ # # SELECT * FROM albums
2847
+ # # SELECT * FROM artists WHERE (id IN (...))
2848
+ # # SELECT * FROM genres WHERE (id IN (...))
2849
+ #
2850
+ # # For each artist, eager load albums and tracks for each album
2851
+ # Artist.eager(albums: :tracks).all
2852
+ # # SELECT * FROM artists
2853
+ # # SELECT * FROM albums WHERE (artist_id IN (...))
2854
+ # # SELECT * FROM tracks WHERE (album_id IN (...))
2855
+ #
2856
+ # # For each artist, eager load albums, tracks for each album, and genre for each track
2857
+ # Artist.eager(albums: {tracks: :genre}).all
2858
+ # # SELECT * FROM artists
2859
+ # # SELECT * FROM albums WHERE (artist_id IN (...))
2860
+ # # SELECT * FROM tracks WHERE (album_id IN (...))
2861
+ # # SELECT * FROM genre WHERE (id IN (...))
2862
+ #
2863
+ # # For each artist, eager load albums with year > 1990
2864
+ # Artist.eager(albums: proc{|ds| ds.where{year > 1990}}).all
2865
+ # # SELECT * FROM artists
2866
+ # # SELECT * FROM albums WHERE ((year > 1990) AND (artist_id IN (...)))
2867
+ #
2868
+ # # For each artist, eager load albums and tracks 1-10 for each album
2869
+ # Artist.eager(albums: {tracks: proc{|ds| ds.where(number: 1..10)}}).all
2870
+ # # SELECT * FROM artists
2871
+ # # SELECT * FROM albums WHERE (artist_id IN (...))
2872
+ # # SELECT * FROM tracks WHERE ((number >= 1) AND (number <= 10) AND (album_id IN (...)))
2873
+ #
2874
+ # # For each artist, eager load albums with year > 1990, and tracks for those albums
2875
+ # Artist.eager(albums: {proc{|ds| ds.where{year > 1990}}=>:tracks}).all
2876
+ # # SELECT * FROM artists
2877
+ # # SELECT * FROM albums WHERE ((year > 1990) AND (artist_id IN (...)))
2878
+ # # SELECT * FROM albums WHERE (artist_id IN (...))
2763
2879
  def eager(*associations)
2764
2880
  opts = @opts[:eager]
2765
2881
  association_opts = eager_options_for_associations(associations)
@@ -2788,6 +2904,78 @@ module Sequel
2788
2904
  #
2789
2905
  # Like +eager+, you need to call +all+ on the dataset for the eager loading to work. If you just
2790
2906
  # call +each+, it will yield plain hashes, each containing all columns from all the tables.
2907
+ #
2908
+ # To modify the associated dataset that will be joined to the current dataset, you should use a
2909
+ # hash for the association, with the key being the association name symbol, and the value being
2910
+ # a callable object that is called with the associated dataset and should return a modified
2911
+ # dataset. If that association also has dependent associations, instead of a callable object,
2912
+ # use a hash with the callable object being the key, and the dependent association(s) as the value.
2913
+ #
2914
+ # You can specify an alias by providing a Sequel::SQL::AliasedExpression object instead of
2915
+ # an a Symbol for the assocation name.
2916
+ #
2917
+ # Examples:
2918
+ #
2919
+ # # For each album, eager_graph load the artist
2920
+ # Album.eager_graph(:artist).all
2921
+ # # SELECT ...
2922
+ # # FROM albums
2923
+ # # LEFT OUTER JOIN artists AS artist ON (artists.id = albums.artist_id)
2924
+ #
2925
+ # # For each album, eager_graph load the artist, using a specified alias
2926
+ # Album.eager_graph(Sequel[:artist].as(:a)).all
2927
+ # # SELECT ...
2928
+ # # FROM albums
2929
+ # # LEFT OUTER JOIN artists AS a ON (a.id = albums.artist_id)
2930
+ #
2931
+ # # For each album, eager_graph load the artist and genre
2932
+ # Album.eager_graph(:artist, :genre).all
2933
+ # Album.eager_graph(:artist).eager_graph(:genre).all
2934
+ # # SELECT ...
2935
+ # # FROM albums
2936
+ # # LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id)
2937
+ # # LEFT OUTER JOIN genres AS genre ON (genre.id = albums.genre_id)
2938
+ #
2939
+ # # For each artist, eager_graph load albums and tracks for each album
2940
+ # Artist.eager_graph(albums: :tracks).all
2941
+ # # SELECT ...
2942
+ # # FROM artists
2943
+ # # LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
2944
+ # # LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
2945
+ #
2946
+ # # For each artist, eager_graph load albums, tracks for each album, and genre for each track
2947
+ # Artist.eager_graph(albums: {tracks: :genre}).all
2948
+ # # SELECT ...
2949
+ # # FROM artists
2950
+ # # LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
2951
+ # # LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
2952
+ # # LEFT OUTER JOIN genres AS genre ON (genre.id = tracks.genre_id)
2953
+ #
2954
+ # # For each artist, eager_graph load albums with year > 1990
2955
+ # Artist.eager_graph(albums: proc{|ds| ds.where{year > 1990}}).all
2956
+ # # SELECT ...
2957
+ # # FROM artists
2958
+ # # LEFT OUTER JOIN (
2959
+ # # SELECT * FROM albums WHERE (year > 1990)
2960
+ # # ) AS albums ON (albums.artist_id = artists.id)
2961
+ #
2962
+ # # For each artist, eager_graph load albums and tracks 1-10 for each album
2963
+ # Artist.eager_graph(albums: {tracks: proc{|ds| ds.where(number: 1..10)}}).all
2964
+ # # SELECT ...
2965
+ # # FROM artists
2966
+ # # LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
2967
+ # # LEFT OUTER JOIN (
2968
+ # # SELECT * FROM tracks WHERE ((number >= 1) AND (number <= 10))
2969
+ # # ) AS tracks ON (tracks.albums_id = albums.id)
2970
+ #
2971
+ # # For each artist, eager_graph load albums with year > 1990, and tracks for those albums
2972
+ # Artist.eager_graph(albums: {proc{|ds| ds.where{year > 1990}}=>:tracks}).all
2973
+ # # SELECT ...
2974
+ # # FROM artists
2975
+ # # LEFT OUTER JOIN (
2976
+ # # SELECT * FROM albums WHERE (year > 1990)
2977
+ # # ) AS albums ON (albums.artist_id = artists.id)
2978
+ # # LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
2791
2979
  def eager_graph(*associations)
2792
2980
  eager_graph_with_options(associations)
2793
2981
  end
@@ -3207,7 +3395,6 @@ module Sequel
3207
3395
  # Hash with table alias symbol keys and [limit, offset] values
3208
3396
  attr_reader :limit_map
3209
3397
 
3210
- # Hash with table alias symbol keys and callable values used to create model instances
3211
3398
  # The table alias symbol for the primary model
3212
3399
  attr_reader :master
3213
3400
 
@@ -1287,11 +1287,11 @@ module Sequel
1287
1287
  # a.update(:name=>'A')
1288
1288
  # end
1289
1289
  #
1290
- # a = Artist[2]
1291
- # Artist.db.transaction do
1292
- # a.lock!('FOR NO KEY UPDATE')
1293
- # a.update(:name=>'B')
1294
- # end
1290
+ # a = Artist[2]
1291
+ # Artist.db.transaction do
1292
+ # a.lock!('FOR NO KEY UPDATE')
1293
+ # a.update(:name=>'B')
1294
+ # end
1295
1295
  def lock!(style=:update)
1296
1296
  _refresh(this.lock_style(style)) unless new?
1297
1297
  self
@@ -1551,8 +1551,8 @@ module Sequel
1551
1551
  update_restricted(hash, :default)
1552
1552
  end
1553
1553
 
1554
- # Update the instances values by calling +set_fields+ with the arguments, then
1555
- # saves any changes to the record. Returns self.
1554
+ # Update the instance's values by calling set_fields with the arguments, then
1555
+ # calls save_changes.
1556
1556
  #
1557
1557
  # artist.update_fields({name: 'Jim'}, [:name])
1558
1558
  # # UPDATE artists SET name = 'Jim' WHERE (id = 1)
@@ -72,14 +72,12 @@ module Sequel
72
72
  # A frozen ruby hash holding all of the model's frozen instances, keyed by frozen primary key.
73
73
  attr_reader :cache
74
74
 
75
- # An array of all of the model's frozen instances, without issuing a database
76
- # query.
77
- def all
78
- if @static_cache_frozen
79
- @all.dup
80
- else
81
- map{|o| o}
82
- end
75
+ # An array of all of the model's instances, without issuing a database
76
+ # query. If a block is given, yields each instance to the block.
77
+ def all(&block)
78
+ array = @static_cache_frozen ? @all.dup : to_a
79
+ array.each(&block) if block
80
+ array
83
81
  end
84
82
 
85
83
  # If a block is given, multiple arguments are given, or a single
@@ -60,6 +60,9 @@ module Sequel
60
60
  # # SELECT * FROM artists WHERE name > 'N' AND id IN (...)
61
61
  # albums.first.artists(eager: lambda{|ds| ds.where(Sequel[:name] > 'N')})
62
62
  #
63
+ # Note that the :eager option only takes effect if the association
64
+ # has not already been loaded for the model.
65
+ #
63
66
  # The tactical_eager_loading plugin also allows transparent eager
64
67
  # loading when calling association methods on associated objects
65
68
  # eagerly loaded via Dataset#eager_graph. This can reduce N queries
@@ -100,6 +103,12 @@ module Sequel
100
103
  # loaded by eager_graph will only take place if the associated classes
101
104
  # also use the tactical_eager_loading plugin.
102
105
  #
106
+ # When using this plugin, calling association methods on separate
107
+ # instances of the same result set is not thread-safe, because this
108
+ # plugin attempts to modify all instances of the same result set
109
+ # to eagerly set the associated objects, and having separate threads
110
+ # modify the same model instance is not thread-safe.
111
+ #
103
112
  # Usage:
104
113
  #
105
114
  # # Make all model subclass instances use tactical eager loading (called before loading subclasses)
@@ -6,7 +6,7 @@ module Sequel
6
6
 
7
7
  # The minor version of Sequel. Bumped for every non-patch level
8
8
  # release, generally around once a month.
9
- MINOR = 12
9
+ MINOR = 13
10
10
 
11
11
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
12
12
  # releases that fix regressions from previous versions.
@@ -2330,6 +2330,11 @@ describe "Dataset#from_self" do
2330
2330
  @ds.from_self(:alias=>:some_name, :column_aliases=>[:c1, :c2]).sql.must_equal 'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name(c1, c2)'
2331
2331
  end
2332
2332
 
2333
+ it "should use the user-specified alias" do
2334
+ @ds.from_self(:alias=>:some_name).sql.must_equal 'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name'
2335
+ @ds.from_self(:alias=>:some_name1).sql.must_equal 'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name1'
2336
+ end
2337
+
2333
2338
  it "should use the user-specified alias for joins" do
2334
2339
  @ds.from_self(:alias=>:some_name).inner_join(:posts, :alias=>:name).sql.must_equal \
2335
2340
  'SELECT * FROM (SELECT name FROM test LIMIT 1) AS some_name INNER JOIN posts ON (posts.alias = some_name.name)'
@@ -3836,6 +3841,7 @@ describe "Dataset prepared statements and bound variables " do
3836
3841
  @ds.filter(:num=>:$n).call([:to_hash, :a, :b], :n=>1)
3837
3842
  @ds.filter(:num=>:$n).call([:to_hash_groups, :a, :b], :n=>1)
3838
3843
  @ds.filter(:num=>:$n).call(:first, :n=>1)
3844
+ @ds.filter(:num=>:$n).call(:single_value, :n=>1)
3839
3845
  @ds.filter(:num=>:$n).call(:delete, :n=>1)
3840
3846
  @ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
3841
3847
  @ds.call(:insert, {:n=>1}, :num=>:$n)
@@ -3849,6 +3855,7 @@ describe "Dataset prepared statements and bound variables " do
3849
3855
  'SELECT * FROM items WHERE (num = 1)',
3850
3856
  'SELECT * FROM items WHERE (num = 1)',
3851
3857
  'SELECT * FROM items WHERE (num = 1) LIMIT 1',
3858
+ 'SELECT * FROM items WHERE (num = 1) LIMIT 1',
3852
3859
  'DELETE FROM items WHERE (num = 1)',
3853
3860
  'UPDATE items SET num = 2 WHERE (num = 1)',
3854
3861
  'INSERT INTO items (num) VALUES (1)',
@@ -3865,13 +3872,14 @@ describe "Dataset prepared statements and bound variables " do
3865
3872
  pss << @ds.filter(:num=>:$n).prepare([:to_hash, :a, :b], :sh)
3866
3873
  pss << @ds.filter(:num=>:$n).prepare([:to_hash_groups, :a, :b], :shg)
3867
3874
  pss << @ds.filter(:num=>:$n).prepare(:first, :fn)
3875
+ pss << @ds.filter(:num=>:$n).prepare(:single_value, :svn)
3868
3876
  pss << @ds.filter(:num=>:$n).prepare(:delete, :dn)
3869
3877
  pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
3870
3878
  pss << @ds.prepare(:insert, :in, :num=>:$n)
3871
3879
  pss << @ds.prepare(:insert_pk, :inp, :num=>:$n)
3872
3880
  pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
3873
- @db.prepared_statements.keys.sort_by{|k| k.to_s}.must_equal [:ah, :dn, :en, :fn, :in, :inp, :ins, :sh, :shg, :sm, :sn, :un]
3874
- [:en, :sn, :sm, :ah, :sh, :shg, :fn, :dn, :un, :in, :inp, :ins].each_with_index{|x, i| @db.prepared_statements[x].must_equal pss[i]}
3881
+ @db.prepared_statements.keys.sort_by{|k| k.to_s}.must_equal [:ah, :dn, :en, :fn, :in, :inp, :ins, :sh, :shg, :sm, :sn, :svn, :un]
3882
+ [:en, :sn, :sm, :ah, :sh, :shg, :fn, :svn, :dn, :un, :in, :inp, :ins].each_with_index{|x, i| @db.prepared_statements[x].must_equal pss[i]}
3875
3883
  @db.call(:en, :n=>1){}
3876
3884
  @db.call(:sn, :n=>1)
3877
3885
  @db.call(:sm, :n=>1)
@@ -3879,6 +3887,7 @@ describe "Dataset prepared statements and bound variables " do
3879
3887
  @db.call(:sh, :n=>1)
3880
3888
  @db.call(:shg, :n=>1)
3881
3889
  @db.call(:fn, :n=>1)
3890
+ @db.call(:svn, :n=>1)
3882
3891
  @db.call(:dn, :n=>1)
3883
3892
  @db.call(:un, :n=>1, :n2=>2)
3884
3893
  @db.call(:in, :n=>1)
@@ -3892,6 +3901,7 @@ describe "Dataset prepared statements and bound variables " do
3892
3901
  'SELECT * FROM items WHERE (num = 1)',
3893
3902
  'SELECT * FROM items WHERE (num = 1)',
3894
3903
  'SELECT * FROM items WHERE (num = 1) LIMIT 1',
3904
+ 'SELECT * FROM items WHERE (num = 1) LIMIT 1',
3895
3905
  'DELETE FROM items WHERE (num = 1)',
3896
3906
  'UPDATE items SET num = 2 WHERE (num = 1)',
3897
3907
  'INSERT INTO items (num) VALUES (1)',
@@ -4032,6 +4042,7 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
4032
4042
  @ps << @ds.prepare(:select, :s)
4033
4043
  @ps << @ds.prepare(:all, :a)
4034
4044
  @ps << @ds.prepare(:first, :f)
4045
+ @ps << @ds.prepare(:single_value, :sv)
4035
4046
  @ps << @ds.prepare(:delete, :d)
4036
4047
  @ps << @ds.prepare(:insert, :i, :num=>:$n)
4037
4048
  @ps << @ds.prepare(:update, :u, :num=>:$n)
@@ -4046,6 +4057,7 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
4046
4057
  @db.sqls.must_equal ["SELECT * FROM items WHERE (num = ?) -- args: [1]",
4047
4058
  "SELECT * FROM items WHERE (num = ?) -- args: [1]",
4048
4059
  "SELECT * FROM items WHERE (num = ?) LIMIT 1 -- args: [1]",
4060
+ "SELECT * FROM items WHERE (num = ?) LIMIT 1 -- args: [1]",
4049
4061
  "DELETE FROM items WHERE (num = ?) -- args: [1]",
4050
4062
  "INSERT INTO items (num) VALUES (?) -- args: [1]",
4051
4063
  "UPDATE items SET num = ? WHERE (num = ?) -- args: [1, 1]"]
@@ -0,0 +1,18 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe "constant_sql_override extension" do
4
+ before do
5
+ @db = Sequel.mock.extension(:constant_sql_override)
6
+ end
7
+
8
+ it 'overrides configured constants' do
9
+ @db.set_constant_sql(Sequel::CURRENT_TIMESTAMP, "CURRENT TIMESTAMP AT TIME ZONE 'UTC'")
10
+ @db[:tbl].where(foo: Sequel::CURRENT_TIMESTAMP).first
11
+ @db.sqls.must_equal ["SELECT * FROM tbl WHERE (foo = CURRENT TIMESTAMP AT TIME ZONE 'UTC') LIMIT 1"]
12
+ end
13
+
14
+ it 'freezes the constant_sqls hash' do
15
+ @db.freeze
16
+ @db.constant_sqls.frozen?.must_equal true
17
+ end
18
+ end
@@ -122,6 +122,10 @@ describe "Sequel::Plugins::StaticCache" do
122
122
  @c.map.frozen?.must_equal false
123
123
  end
124
124
 
125
+ it "should have map without a block return an Enumerator" do
126
+ @c.map.class.must_equal Enumerator
127
+ end
128
+
125
129
  it "should have map with a block and argument raise" do
126
130
  proc{@c.map(:id){}}.must_raise(Sequel::Error)
127
131
  end
@@ -148,6 +152,14 @@ describe "Sequel::Plugins::StaticCache" do
148
152
  @c.all.must_equal [@c1, @c2]
149
153
  end
150
154
 
155
+ it "should have all receiving block" do
156
+ a = []
157
+ b = @c.all { |o| a << o }
158
+ a.must_equal [@c1, @c2]
159
+ a.must_equal b
160
+ @db.sqls.must_equal []
161
+ end
162
+
151
163
  it "should have as_hash/to_hash without arguments run without a query" do
152
164
  a = @c.to_hash
153
165
  a.must_equal(1=>@c1, 2=>@c2)
@@ -21,6 +21,7 @@ describe "Prepared Statements and Bound Arguments" do
21
21
  @ds.filter(:numb=>:$n).call(:select, :n=>10).must_equal [{:id=>1, :numb=>10}]
22
22
  @ds.filter(:numb=>:$n).call(:all, :n=>10).must_equal [{:id=>1, :numb=>10}]
23
23
  @ds.filter(:numb=>:$n).call(:first, :n=>10).must_equal(:id=>1, :numb=>10)
24
+ @ds.select(:numb).filter(:numb=>:$n).call(:single_value, :n=>10).must_equal(10)
24
25
  @ds.filter(:numb=>:$n).call([:map, :numb], :n=>10).must_equal [10]
25
26
  @ds.filter(:numb=>:$n).call([:as_hash, :id, :numb], :n=>10).must_equal(1=>10)
26
27
  @ds.filter(:numb=>:$n).call([:to_hash, :id, :numb], :n=>10).must_equal(1=>10)
@@ -39,20 +40,24 @@ describe "Prepared Statements and Bound Arguments" do
39
40
  @ds.filter(:numb=>:$n).bind(:n=>10).call(:select).must_equal [{:id=>1, :numb=>10}]
40
41
  @ds.filter(:numb=>:$n).bind(:n=>10).call(:all).must_equal [{:id=>1, :numb=>10}]
41
42
  @ds.filter(:numb=>:$n).bind(:n=>10).call(:first).must_equal(:id=>1, :numb=>10)
43
+ @ds.select(:numb).filter(:numb=>:$n).bind(:n=>10).call(:single_value).must_equal(10)
42
44
 
43
45
  @ds.bind(:n=>10).filter(:numb=>:$n).call(:select).must_equal [{:id=>1, :numb=>10}]
44
46
  @ds.bind(:n=>10).filter(:numb=>:$n).call(:all).must_equal [{:id=>1, :numb=>10}]
45
47
  @ds.bind(:n=>10).filter(:numb=>:$n).call(:first).must_equal(:id=>1, :numb=>10)
48
+ @ds.bind(:n=>10).select(:numb).filter(:numb=>:$n).call(:single_value).must_equal(10)
46
49
  end
47
50
 
48
51
  it "should allow overriding variables specified with #bind" do
49
52
  @ds.filter(:numb=>:$n).bind(:n=>1).call(:select, :n=>10).must_equal [{:id=>1, :numb=>10}]
50
53
  @ds.filter(:numb=>:$n).bind(:n=>1).call(:all, :n=>10).must_equal [{:id=>1, :numb=>10}]
51
54
  @ds.filter(:numb=>:$n).bind(:n=>1).call(:first, :n=>10).must_equal(:id=>1, :numb=>10)
55
+ @ds.select(:numb).filter(:numb=>:$n).bind(:n=>1).call(:single_value, :n=>10).must_equal(10)
52
56
 
53
57
  @ds.filter(:numb=>:$n).bind(:n=>1).bind(:n=>10).call(:select).must_equal [{:id=>1, :numb=>10}]
54
58
  @ds.filter(:numb=>:$n).bind(:n=>1).bind(:n=>10).call(:all).must_equal [{:id=>1, :numb=>10}]
55
59
  @ds.filter(:numb=>:$n).bind(:n=>1).bind(:n=>10).call(:first).must_equal(:id=>1, :numb=>10)
60
+ @ds.select(:numb).filter(:numb=>:$n).bind(:n=>1).bind(:n=>10).call(:single_value).must_equal(10)
56
61
  end
57
62
 
58
63
  it "should support placeholder literal strings with call" do
@@ -160,6 +165,8 @@ describe "Prepared Statements and Bound Arguments" do
160
165
  @db.call(:select_n, :n=>10).must_equal [{:id=>1, :numb=>10}]
161
166
  @ds.filter(:numb=>:$n).prepare(:first, :select_n)
162
167
  @db.call(:select_n, :n=>10).must_equal(:id=>1, :numb=>10)
168
+ @ds.select(:numb).filter(:numb=>:$n).prepare(:single_value, :select_n)
169
+ @db.call(:select_n, :n=>10).must_equal(10)
163
170
  @ds.filter(:numb=>:$n).prepare([:map, :numb], :select_n)
164
171
  @db.call(:select_n, :n=>10).must_equal [10]
165
172
  @ds.filter(:numb=>:$n).prepare([:as_hash, :id, :numb], :select_n)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.12.0
4
+ version: 5.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-31 00:00:00.000000000 Z
11
+ date: 2018-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -196,6 +196,7 @@ extra_rdoc_files:
196
196
  - doc/release_notes/5.10.0.txt
197
197
  - doc/release_notes/5.11.0.txt
198
198
  - doc/release_notes/5.12.0.txt
199
+ - doc/release_notes/5.13.0.txt
199
200
  files:
200
201
  - CHANGELOG
201
202
  - MIT-LICENSE
@@ -278,6 +279,7 @@ files:
278
279
  - doc/release_notes/5.10.0.txt
279
280
  - doc/release_notes/5.11.0.txt
280
281
  - doc/release_notes/5.12.0.txt
282
+ - doc/release_notes/5.13.0.txt
281
283
  - doc/release_notes/5.2.0.txt
282
284
  - doc/release_notes/5.3.0.txt
283
285
  - doc/release_notes/5.4.0.txt
@@ -384,6 +386,7 @@ files:
384
386
  - lib/sequel/extensions/columns_introspection.rb
385
387
  - lib/sequel/extensions/connection_expiration.rb
386
388
  - lib/sequel/extensions/connection_validator.rb
389
+ - lib/sequel/extensions/constant_sql_override.rb
387
390
  - lib/sequel/extensions/constraint_validations.rb
388
391
  - lib/sequel/extensions/core_extensions.rb
389
392
  - lib/sequel/extensions/core_refinements.rb
@@ -590,6 +593,7 @@ files:
590
593
  - spec/extensions/composition_spec.rb
591
594
  - spec/extensions/connection_expiration_spec.rb
592
595
  - spec/extensions/connection_validator_spec.rb
596
+ - spec/extensions/constant_sql_override_spec.rb
593
597
  - spec/extensions/constraint_validations_plugin_spec.rb
594
598
  - spec/extensions/constraint_validations_spec.rb
595
599
  - spec/extensions/core_refinements_spec.rb