sequel 3.29.0 → 3.30.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +35 -3
- data/Rakefile +2 -1
- data/doc/association_basics.rdoc +11 -0
- data/doc/opening_databases.rdoc +2 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/testing.rdoc +17 -3
- data/lib/sequel/adapters/amalgalite.rb +2 -2
- data/lib/sequel/adapters/do/mysql.rb +5 -2
- data/lib/sequel/adapters/ibmdb.rb +2 -2
- data/lib/sequel/adapters/jdbc.rb +126 -43
- data/lib/sequel/adapters/jdbc/as400.rb +11 -3
- data/lib/sequel/adapters/jdbc/db2.rb +2 -1
- data/lib/sequel/adapters/jdbc/derby.rb +44 -19
- data/lib/sequel/adapters/jdbc/h2.rb +32 -19
- data/lib/sequel/adapters/jdbc/hsqldb.rb +21 -17
- data/lib/sequel/adapters/jdbc/jtds.rb +9 -4
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +2 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +21 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +48 -18
- data/lib/sequel/adapters/mock.rb +2 -1
- data/lib/sequel/adapters/mysql.rb +4 -2
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/openbase.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +6 -6
- data/lib/sequel/adapters/postgres.rb +25 -12
- data/lib/sequel/adapters/shared/access.rb +14 -6
- data/lib/sequel/adapters/shared/db2.rb +36 -13
- data/lib/sequel/adapters/shared/firebird.rb +12 -5
- data/lib/sequel/adapters/shared/informix.rb +11 -3
- data/lib/sequel/adapters/shared/mssql.rb +94 -47
- data/lib/sequel/adapters/shared/mysql.rb +107 -49
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
- data/lib/sequel/adapters/shared/oracle.rb +54 -27
- data/lib/sequel/adapters/shared/postgres.rb +65 -26
- data/lib/sequel/adapters/shared/progress.rb +4 -1
- data/lib/sequel/adapters/shared/sqlite.rb +36 -20
- data/lib/sequel/adapters/sqlite.rb +2 -3
- data/lib/sequel/adapters/swift/mysql.rb +3 -2
- data/lib/sequel/adapters/swift/sqlite.rb +2 -2
- data/lib/sequel/adapters/tinytds.rb +14 -8
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -4
- data/lib/sequel/database/misc.rb +6 -2
- data/lib/sequel/dataset/graph.rb +33 -7
- data/lib/sequel/dataset/prepared_statements.rb +19 -5
- data/lib/sequel/dataset/sql.rb +611 -201
- data/lib/sequel/model/associations.rb +12 -5
- data/lib/sequel/model/base.rb +20 -5
- data/lib/sequel/plugins/sharding.rb +9 -29
- data/lib/sequel/sql.rb +2 -1
- data/lib/sequel/timezones.rb +14 -4
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +10 -0
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/core/core_sql_spec.rb +3 -1
- data/spec/core/database_spec.rb +42 -0
- data/spec/core/dataset_spec.rb +10 -3
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/object_graph_spec.rb +38 -0
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +35 -39
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +30 -82
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +33 -103
- data/spec/extensions/instance_filters_spec.rb +10 -21
- data/spec/extensions/instance_hooks_spec.rb +6 -24
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +135 -277
- data/spec/extensions/migration_spec.rb +18 -15
- data/spec/extensions/named_timezones_spec.rb +1 -1
- data/spec/extensions/nested_attributes_spec.rb +97 -92
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +22 -37
- data/spec/extensions/prepared_statements_safe_spec.rb +9 -27
- data/spec/extensions/prepared_statements_spec.rb +11 -30
- data/spec/extensions/prepared_statements_with_pk_spec.rb +6 -13
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +3 -6
- data/spec/extensions/serialization_spec.rb +20 -32
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +14 -36
- data/spec/extensions/spec_helper.rb +10 -64
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +1 -2
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/integration/dataset_test.rb +16 -4
- data/spec/integration/prepared_statement_test.rb +4 -2
- data/spec/model/eager_loading_spec.rb +16 -0
- data/spec/model/model_spec.rb +15 -1
- data/spec/model/record_spec.rb +60 -0
- metadata +23 -40
@@ -718,6 +718,10 @@ module Sequel
|
|
718
718
|
# :eager_loader_key :: A symbol for the key column to use to populate the key hash
|
719
719
|
# for the eager loader.
|
720
720
|
# :extend :: A module or array of modules to extend the dataset with.
|
721
|
+
# :graph_alias_base :: The base name to use for the table alias when eager graphing. Defaults to the name
|
722
|
+
# of the association. If the alias name has already been used in the query, Sequel will create
|
723
|
+
# a unique alias by appending a numeric suffix (e.g. alias_0, alias_1, ...) until the alias is
|
724
|
+
# unique.
|
721
725
|
# :graph_block :: The block to pass to join_table when eagerly loading
|
722
726
|
# the association via +eager_graph+.
|
723
727
|
# :graph_conditions :: The additional conditions to use on the SQL join when eagerly loading
|
@@ -822,6 +826,7 @@ module Sequel
|
|
822
826
|
opts[:graph_join_type] ||= :left_outer
|
823
827
|
opts[:order_eager_graph] = true unless opts.include?(:order_eager_graph)
|
824
828
|
conds = opts[:conditions]
|
829
|
+
opts[:graph_alias_base] ||= name
|
825
830
|
opts[:graph_conditions] = conds if !opts.include?(:graph_conditions) and Sequel.condition_specifier?(conds)
|
826
831
|
opts[:graph_conditions] = opts.fetch(:graph_conditions, []).to_a
|
827
832
|
opts[:graph_select] = Array(opts[:graph_select]) if opts[:graph_select]
|
@@ -1618,7 +1623,7 @@ module Sequel
|
|
1618
1623
|
# association and the values of the foreign/primary keys of +y+. For most association
|
1619
1624
|
# types, this is a simple transformation, but for +many_to_many+ associations this
|
1620
1625
|
# creates a subquery to the join table.
|
1621
|
-
def
|
1626
|
+
def complex_expression_sql_append(sql, op, args)
|
1622
1627
|
r = args.at(1)
|
1623
1628
|
if (((op == :'=' || op == :'!=') and r.is_a?(Sequel::Model)) ||
|
1624
1629
|
(multiple = ((op == :IN || op == :'NOT IN') and ((is_ds = r.is_a?(Sequel::Dataset)) or r.all?{|x| x.is_a?(Sequel::Model)}))))
|
@@ -1646,7 +1651,7 @@ module Sequel
|
|
1646
1651
|
end
|
1647
1652
|
|
1648
1653
|
if exp = association_filter_expression(op, ar, r)
|
1649
|
-
|
1654
|
+
literal_append(sql, exp)
|
1650
1655
|
else
|
1651
1656
|
raise Sequel::Error, "invalid association type #{ar[:type].inspect} for association #{l.inspect} used in dataset filter for model #{model.inspect}"
|
1652
1657
|
end
|
@@ -1725,8 +1730,10 @@ module Sequel
|
|
1725
1730
|
# Like +eager+, you need to call +all+ on the dataset for the eager loading to work. If you just
|
1726
1731
|
# call +each+, it will yield plain hashes, each containing all columns from all the tables.
|
1727
1732
|
def eager_graph(*associations)
|
1728
|
-
ds = if @opts[:eager_graph]
|
1729
|
-
|
1733
|
+
ds = if eg = @opts[:eager_graph]
|
1734
|
+
eg = eg.dup
|
1735
|
+
[:requirements, :reflections, :reciprocals].each{|k| eg[k] = eg[k].dup}
|
1736
|
+
clone(:eager_graph=>eg)
|
1730
1737
|
else
|
1731
1738
|
# Each of the following have a symbol key for the table alias, with the following values:
|
1732
1739
|
# :reciprocals - the reciprocal instance variable to use for this association
|
@@ -1761,7 +1768,7 @@ module Sequel
|
|
1761
1768
|
# *associations :: any associations dependent on this one
|
1762
1769
|
def eager_graph_association(ds, model, ta, requirements, r, *associations)
|
1763
1770
|
assoc_name = r[:name]
|
1764
|
-
assoc_table_alias = ds.unused_table_alias(
|
1771
|
+
assoc_table_alias = ds.unused_table_alias(r[:graph_alias_base])
|
1765
1772
|
loader = r[:eager_grapher]
|
1766
1773
|
if !associations.empty?
|
1767
1774
|
if associations.first.respond_to?(:call)
|
data/lib/sequel/model/base.rb
CHANGED
@@ -1139,13 +1139,16 @@ module Sequel
|
|
1139
1139
|
# Takes the following options:
|
1140
1140
|
#
|
1141
1141
|
# :changed :: save all changed columns, instead of all columns or the columns given
|
1142
|
+
# :raise_on_failure :: set to true or false to override the current
|
1143
|
+
# +raise_on_save_failure+ setting
|
1144
|
+
# :server :: set the server/shard on the object before saving, and use that
|
1145
|
+
# server/shard in any transaction.
|
1142
1146
|
# :transaction :: set to true or false to override the current
|
1143
1147
|
# +use_transactions+ setting
|
1144
1148
|
# :validate :: set to false to skip validation
|
1145
|
-
# :raise_on_failure :: set to true or false to override the current
|
1146
|
-
# +raise_on_save_failure+ setting
|
1147
1149
|
def save(*columns)
|
1148
1150
|
opts = columns.last.is_a?(Hash) ? columns.pop : {}
|
1151
|
+
set_server(opts[:server]) if opts[:server]
|
1149
1152
|
if opts[:validate] != false
|
1150
1153
|
unless checked_save_failure(opts){_valid?(true, opts)}
|
1151
1154
|
raise(ValidationFailed.new(errors)) if raise_on_failure?(opts)
|
@@ -1225,6 +1228,13 @@ module Sequel
|
|
1225
1228
|
set_restricted(hash, only.flatten, false)
|
1226
1229
|
end
|
1227
1230
|
|
1231
|
+
# Set the shard that this object is tied to. Returns self.
|
1232
|
+
def set_server(s)
|
1233
|
+
@server = s
|
1234
|
+
@this.opts[:server] = s if @this
|
1235
|
+
self
|
1236
|
+
end
|
1237
|
+
|
1228
1238
|
# Replace the current values with hash. Should definitely not be
|
1229
1239
|
# used with untrusted input, and should probably not be called
|
1230
1240
|
# directly by user code.
|
@@ -1243,7 +1253,7 @@ module Sequel
|
|
1243
1253
|
# Artist[1].this
|
1244
1254
|
# # SELECT * FROM artists WHERE (id = 1) LIMIT 1
|
1245
1255
|
def this
|
1246
|
-
@this ||= model.dataset.filter(pk_hash).limit(1).naked
|
1256
|
+
@this ||= use_server(model.dataset.filter(pk_hash).limit(1).naked)
|
1247
1257
|
end
|
1248
1258
|
|
1249
1259
|
# Runs #set with the passed hash and then runs save_changes.
|
@@ -1382,7 +1392,7 @@ module Sequel
|
|
1382
1392
|
# The dataset to use when inserting a new object. The same as the model's
|
1383
1393
|
# dataset by default.
|
1384
1394
|
def _insert_dataset
|
1385
|
-
model.dataset
|
1395
|
+
use_server(model.dataset)
|
1386
1396
|
end
|
1387
1397
|
|
1388
1398
|
# Insert into the given dataset and return the primary key created (if any).
|
@@ -1676,6 +1686,11 @@ module Sequel
|
|
1676
1686
|
set_restricted(hash, only, except)
|
1677
1687
|
save_changes
|
1678
1688
|
end
|
1689
|
+
|
1690
|
+
# Set the given dataset to use the current object's shard.
|
1691
|
+
def use_server(ds)
|
1692
|
+
@server ? ds.server(@server) : ds
|
1693
|
+
end
|
1679
1694
|
|
1680
1695
|
# Whether to use a transaction for this action. If the :transaction
|
1681
1696
|
# option is present in the hash, use that, otherwise, fallback to the
|
@@ -1716,7 +1731,7 @@ module Sequel
|
|
1716
1731
|
# # ...
|
1717
1732
|
def destroy
|
1718
1733
|
pr = proc{all{|r| r.destroy}.length}
|
1719
|
-
model.use_transactions ? @db.transaction(&pr) : pr.call
|
1734
|
+
model.use_transactions ? @db.transaction(:server=>opts[:server], &pr) : pr.call
|
1720
1735
|
end
|
1721
1736
|
|
1722
1737
|
# This allows you to call +to_hash+ without any arguments, which will
|
@@ -1,13 +1,14 @@
|
|
1
1
|
module Sequel
|
2
2
|
module Plugins
|
3
|
-
# The sharding plugin
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
3
|
+
# The sharding plugin augments Sequel's default model sharding support
|
4
|
+
# in the following ways:
|
5
|
+
#
|
6
|
+
# 1) It automatically sets model instances to be saved back to the
|
7
|
+
# shard they were retreived from.
|
8
|
+
# 2) It makes model associations use the same shard as the model
|
9
|
+
# object.
|
10
|
+
# 3) It adds a slightly nicer API for creating model instances on
|
11
|
+
# specific shards.
|
11
12
|
#
|
12
13
|
# Usage:
|
13
14
|
#
|
@@ -55,12 +56,6 @@ module Sequel
|
|
55
56
|
end
|
56
57
|
|
57
58
|
module InstanceMethods
|
58
|
-
# Set the shard that this object is tied to. Returns self.
|
59
|
-
def set_server(s)
|
60
|
-
@server = s
|
61
|
-
self
|
62
|
-
end
|
63
|
-
|
64
59
|
# Set the server that this object is tied to, unless it has
|
65
60
|
# already been set. Returns self.
|
66
61
|
def set_server?(s)
|
@@ -68,11 +63,6 @@ module Sequel
|
|
68
63
|
self
|
69
64
|
end
|
70
65
|
|
71
|
-
# Ensure that the instance dataset is tied to the correct shard.
|
72
|
-
def this
|
73
|
-
use_server(super)
|
74
|
-
end
|
75
|
-
|
76
66
|
private
|
77
67
|
|
78
68
|
# Ensure that association datasets are tied to the correct shard.
|
@@ -80,11 +70,6 @@ module Sequel
|
|
80
70
|
use_server(super)
|
81
71
|
end
|
82
72
|
|
83
|
-
# Ensure that the object is inserted into the correct shard.
|
84
|
-
def _insert_dataset
|
85
|
-
use_server(super)
|
86
|
-
end
|
87
|
-
|
88
73
|
# Ensure that the join table for many_to_many associations uses the correct shard.
|
89
74
|
def _join_table_dataset(opts)
|
90
75
|
use_server(super)
|
@@ -97,11 +82,6 @@ module Sequel
|
|
97
82
|
o.set_server?(@server) if o.respond_to?(:set_server?)
|
98
83
|
super
|
99
84
|
end
|
100
|
-
|
101
|
-
# Set the given dataset to use the current object's shard.
|
102
|
-
def use_server(ds)
|
103
|
-
@server ? ds.server(@server) : ds
|
104
|
-
end
|
105
85
|
end
|
106
86
|
|
107
87
|
module DatasetMethods
|
data/lib/sequel/sql.rb
CHANGED
@@ -79,7 +79,8 @@ module Sequel
|
|
79
79
|
# the method provided on the dataset with args as the argument (self by default).
|
80
80
|
# Used to DRY up some code.
|
81
81
|
def self.to_s_method(meth, args=:self) # :nodoc:
|
82
|
-
class_eval("def to_s(ds)
|
82
|
+
class_eval("def to_s(ds) ds.#{meth}(#{args}) end", __FILE__, __LINE__)
|
83
|
+
class_eval("def to_s_append(ds, sql) ds.#{meth}_append(sql, #{args}) end", __FILE__, __LINE__)
|
83
84
|
end
|
84
85
|
private_class_method :to_s_method
|
85
86
|
|
data/lib/sequel/timezones.rb
CHANGED
@@ -145,14 +145,24 @@ module Sequel
|
|
145
145
|
v2
|
146
146
|
end
|
147
147
|
when Array
|
148
|
-
y, mo, d, h, mi, s = v
|
148
|
+
y, mo, d, h, mi, s, ns, off = v
|
149
149
|
if datetime_class == DateTime
|
150
|
-
|
150
|
+
s += (defined?(Rational) ? Rational(ns, 1000000000) : ns/1000000000.0) if ns
|
151
|
+
if off
|
152
|
+
DateTime.civil(y, mo, d, h, mi, s, off)
|
153
|
+
else
|
154
|
+
convert_input_datetime_no_offset(DateTime.civil(y, mo, d, h, mi, s), input_timezone)
|
155
|
+
end
|
151
156
|
else
|
152
|
-
Time.send(input_timezone == :utc ? :utc : :local, y, mo, d, h, mi, s)
|
157
|
+
Time.send(input_timezone == :utc ? :utc : :local, y, mo, d, h, mi, s, (ns ? ns / 1000.0 : 0))
|
153
158
|
end
|
154
159
|
when Hash
|
155
|
-
|
160
|
+
ary = [:year, :month, :day, :hour, :minute, :second, :nanos].map{|x| (v[x] || v[x.to_s]).to_i}
|
161
|
+
if (offset = (v[:offset] || v['offset']))
|
162
|
+
ary << offset
|
163
|
+
end
|
164
|
+
convert_input_timestamp(ary, input_timezone)
|
165
|
+
convert_input_timestamp(ary, input_timezone)
|
156
166
|
when Time
|
157
167
|
if datetime_class == DateTime
|
158
168
|
v.respond_to?(:to_datetime) ? v.to_datetime : string_to_datetime(v.iso8601)
|
data/lib/sequel/version.rb
CHANGED
@@ -3,7 +3,7 @@ module Sequel
|
|
3
3
|
MAJOR = 3
|
4
4
|
# The minor version of Sequel. Bumped for every non-patch level
|
5
5
|
# release, generally around once a month.
|
6
|
-
MINOR =
|
6
|
+
MINOR = 30
|
7
7
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
8
8
|
# releases that fix regressions from previous versions.
|
9
9
|
TINY = 0
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -247,6 +247,16 @@ describe "A MySQL dataset" do
|
|
247
247
|
|
248
248
|
@d.first[:name].should == ':\\'
|
249
249
|
end
|
250
|
+
|
251
|
+
specify "should handle prepared statements with on_duplicate_key_update" do
|
252
|
+
@d.db.add_index :items, :value, :unique=>true
|
253
|
+
ds = @d.on_duplicate_key_update
|
254
|
+
ps = ds.prepare(:insert, :insert_user_id_feature_name, :value => :$v, :name => :$n)
|
255
|
+
ps.call(:v => 1, :n => 'a')
|
256
|
+
ds.all.should == [{:value=>1, :name=>'a'}]
|
257
|
+
ps.call(:v => 1, :n => 'b')
|
258
|
+
ds.all.should == [{:value=>1, :name=>'b'}]
|
259
|
+
end
|
250
260
|
end
|
251
261
|
|
252
262
|
describe "MySQL datasets" do
|
@@ -187,7 +187,7 @@ describe "An Oracle dataset" do
|
|
187
187
|
@d << {:name => 'def', :value => 789}
|
188
188
|
@d.filter('value > 500').update(:date_created => "to_timestamp('2009-09-09', 'YYYY-MM-DD')".lit)
|
189
189
|
|
190
|
-
@d[:name => 'def'][:date_created].should ==
|
190
|
+
@d[:name => 'def'][:date_created].strftime('%F').should == '2009-09-09'
|
191
191
|
end
|
192
192
|
|
193
193
|
specify "should delete records correctly" do
|
data/spec/core/core_sql_spec.rb
CHANGED
@@ -177,7 +177,9 @@ end
|
|
177
177
|
describe "Column references" do
|
178
178
|
before do
|
179
179
|
@ds = Sequel::Database.new.dataset
|
180
|
-
def @ds.
|
180
|
+
def @ds.quoted_identifier_append(sql, c)
|
181
|
+
sql << "`#{c}`"
|
182
|
+
end
|
181
183
|
@ds.quote_identifiers = true
|
182
184
|
end
|
183
185
|
|
data/spec/core/database_spec.rb
CHANGED
@@ -739,6 +739,13 @@ describe "Database#transaction" do
|
|
739
739
|
proc{@db.after_rollback}.should raise_error(Sequel::Error)
|
740
740
|
end
|
741
741
|
|
742
|
+
specify "should have after_commit and after_rollback respect :server option" do
|
743
|
+
@db.transaction(:server=>:test){@db.after_commit(:server=>:test){@db.execute('foo', :server=>:test)}}
|
744
|
+
@db.sqls.should == ['BEGIN -- test', 'COMMIT -- test', 'foo -- test']
|
745
|
+
@db.transaction(:server=>:test){@db.after_rollback(:server=>:test){@db.execute('foo', :server=>:test)}; raise Sequel::Rollback}
|
746
|
+
@db.sqls.should == ['BEGIN -- test', 'ROLLBACK -- test', 'foo -- test']
|
747
|
+
end
|
748
|
+
|
742
749
|
specify "should execute after_commit outside transactions" do
|
743
750
|
@db.after_commit{@db.execute('foo')}
|
744
751
|
@db.sqls.should == ['foo']
|
@@ -1774,6 +1781,41 @@ describe "Database#typecast_value" do
|
|
1774
1781
|
end
|
1775
1782
|
end
|
1776
1783
|
|
1784
|
+
specify "should handle arrays when typecasting timestamps" do
|
1785
|
+
begin
|
1786
|
+
@db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14]).should == Time.local(2011, 10, 11, 12, 13, 14)
|
1787
|
+
@db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14, 500000000]).should == Time.local(2011, 10, 11, 12, 13, 14, 500000)
|
1788
|
+
|
1789
|
+
Sequel.datetime_class = DateTime
|
1790
|
+
@db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14]).should == DateTime.civil(2011, 10, 11, 12, 13, 14)
|
1791
|
+
@db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14, 500000000]).should == DateTime.civil(2011, 10, 11, 12, 13, (defined?(Rational) ? Rational(29, 2) : 14.5))
|
1792
|
+
@db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14, 500000000, (defined?(Rational) ? Rational(1, 2) : 0.5)]).should == DateTime.civil(2011, 10, 11, 12, 13, (defined?(Rational) ? Rational(29, 2) : 14.5), (defined?(Rational) ? Rational(1, 2) : 0.5))
|
1793
|
+
ensure
|
1794
|
+
Sequel.datetime_class = Time
|
1795
|
+
end
|
1796
|
+
end
|
1797
|
+
|
1798
|
+
specify "should handle hashes when typecasting timestamps" do
|
1799
|
+
begin
|
1800
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14).should == Time.local(2011, 10, 11, 12, 13, 14)
|
1801
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000).should == Time.local(2011, 10, 11, 12, 13, 14, 500000)
|
1802
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14).should == Time.local(2011, 10, 11, 12, 13, 14)
|
1803
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000).should == Time.local(2011, 10, 11, 12, 13, 14, 500000)
|
1804
|
+
|
1805
|
+
Sequel.datetime_class = DateTime
|
1806
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14).should == DateTime.civil(2011, 10, 11, 12, 13, 14)
|
1807
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000).should == DateTime.civil(2011, 10, 11, 12, 13, (defined?(Rational) ? Rational(29, 2) : 14.5))
|
1808
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14).should == DateTime.civil(2011, 10, 11, 12, 13, 14)
|
1809
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000).should == DateTime.civil(2011, 10, 11, 12, 13, (defined?(Rational) ? Rational(29, 2) : 14.5))
|
1810
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :offset=>(defined?(Rational) ? Rational(1, 2) : 0.5)).should == DateTime.civil(2011, 10, 11, 12, 13, 14, (defined?(Rational) ? Rational(1, 2) : 0.5))
|
1811
|
+
@db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000, :offset=>(defined?(Rational) ? Rational(1, 2) : 0.5)).should == DateTime.civil(2011, 10, 11, 12, 13, (defined?(Rational) ? Rational(29, 2) : 14.5), (defined?(Rational) ? Rational(1, 2) : 0.5))
|
1812
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'offset'=>(defined?(Rational) ? Rational(1, 2) : 0.5)).should == DateTime.civil(2011, 10, 11, 12, 13, 14, (defined?(Rational) ? Rational(1, 2) : 0.5))
|
1813
|
+
@db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000, 'offset'=>(defined?(Rational) ? Rational(1, 2) : 0.5)).should == DateTime.civil(2011, 10, 11, 12, 13, (defined?(Rational) ? Rational(29, 2) : 14.5), (defined?(Rational) ? Rational(1, 2) : 0.5))
|
1814
|
+
ensure
|
1815
|
+
Sequel.datetime_class = Time
|
1816
|
+
end
|
1817
|
+
end
|
1818
|
+
|
1777
1819
|
specify "should typecast decimal values to BigDecimal" do
|
1778
1820
|
[1.0, 1, '1.0', BigDecimal('1.0')].each do |i|
|
1779
1821
|
v = @db.typecast_value(:decimal, i)
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -3066,6 +3066,13 @@ describe "Dataset prepared statements and bound variables " do
|
|
3066
3066
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
3067
3067
|
end
|
3068
3068
|
|
3069
|
+
specify "should handle columns on prepared statements correctly" do
|
3070
|
+
@db.columns = [:num]
|
3071
|
+
@ds.meta_def(:select_where_sql){|sql| super(sql); sql << " OR #{columns.first} = 1" if opts[:where]}
|
3072
|
+
@ds.filter(:num=>:$n).prepare(:select, :sn).sql.should == 'SELECT * FROM items WHERE (num = $n) OR num = 1'
|
3073
|
+
@db.sqls.should == ['SELECT * FROM items LIMIT 1']
|
3074
|
+
end
|
3075
|
+
|
3069
3076
|
specify "should handle datasets using static sql and placeholders" do
|
3070
3077
|
@db["SELECT * FROM items WHERE (num = ?)", :$n].call(:select, :n=>1)
|
3071
3078
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)']
|
@@ -3412,7 +3419,7 @@ describe "Sequel::Dataset #with and #with_recursive" do
|
|
3412
3419
|
|
3413
3420
|
specify "#with should work on insert, update, and delete statements if they support it" do
|
3414
3421
|
[:insert, :update, :delete].each do |m|
|
3415
|
-
@ds.meta_def(:"#{m}_clause_methods"){
|
3422
|
+
@ds.meta_def(:"#{m}_clause_methods"){[:"#{m}_with_sql"] + super()}
|
3416
3423
|
end
|
3417
3424
|
@ds.with(:t, @db[:x]).insert_sql(1).should == 'WITH t AS (SELECT * FROM x) INSERT INTO t VALUES (1)'
|
3418
3425
|
@ds.with(:t, @db[:x]).update_sql(:foo=>1).should == 'WITH t AS (SELECT * FROM x) UPDATE t SET foo = 1'
|
@@ -3888,8 +3895,8 @@ describe "Dataset emulating bitwise operator support" do
|
|
3888
3895
|
before do
|
3889
3896
|
@ds = Sequel::Database.new.dataset
|
3890
3897
|
@ds.quote_identifiers = true
|
3891
|
-
def @ds.
|
3892
|
-
complex_expression_arg_pairs(args){|a, b| "bitand(#{literal(a)}, #{literal(b)})"}
|
3898
|
+
def @ds.complex_expression_sql_append(sql, op, args)
|
3899
|
+
sql << complex_expression_arg_pairs(args){|a, b| "bitand(#{literal(a)}, #{literal(b)})"}
|
3893
3900
|
end
|
3894
3901
|
end
|
3895
3902
|
|
@@ -7,6 +7,10 @@ describe "Sequel Mock Adapter" do
|
|
7
7
|
db.adapter_scheme.should == :mock
|
8
8
|
end
|
9
9
|
|
10
|
+
specify "should have constructor accept no arguments" do
|
11
|
+
Sequel::Mock::Database.new.should be_a_kind_of(Sequel::Mock::Database)
|
12
|
+
end
|
13
|
+
|
10
14
|
specify "should each not return any rows by default" do
|
11
15
|
called = false
|
12
16
|
Sequel.mock[:t].each{|r| called = true}
|
@@ -28,11 +28,49 @@ describe Sequel::Dataset, " graphing" do
|
|
28
28
|
ds1.opts.should_not == o1
|
29
29
|
end
|
30
30
|
|
31
|
+
it "#graph should not modify the current dataset's opts if current dataset is already graphed" do
|
32
|
+
ds2 = @ds1.graph(@ds2)
|
33
|
+
proc{@ds1.graph(@ds2)}.should_not raise_error
|
34
|
+
proc{ds2.graph(@ds3)}.should_not raise_error
|
35
|
+
proc{ds2.graph(@ds3)}.should_not raise_error
|
36
|
+
end
|
37
|
+
|
31
38
|
it "#graph should accept a simple dataset and pass the table to join" do
|
32
39
|
ds = @ds1.graph(@ds2, :x=>:id)
|
33
40
|
ds.sql.should == 'SELECT points.id, points.x, points.y, lines.id AS lines_id, lines.x AS lines_x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
|
34
41
|
end
|
35
42
|
|
43
|
+
it "#graph should use currently selected columns as the basis for the selected columns in a new graph" do
|
44
|
+
ds = @ds1.select(:id).graph(@ds2, :x=>:id)
|
45
|
+
ds.sql.should == 'SELECT points.id, lines.id AS lines_id, lines.x, lines.y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
|
46
|
+
ds._fetch = {:id=>1, :lines_id=>2, :x=>3, :y=>4, :graph_id=>5}
|
47
|
+
ds.all.should == [{:points=>{:id=>1}, :lines=>{:id=>2, :x=>3, :y=>4, :graph_id=>5}}]
|
48
|
+
|
49
|
+
ds = @ds1.select(:id, :x).graph(@ds2, :x=>:id)
|
50
|
+
ds.sql.should == 'SELECT points.id, points.x, lines.id AS lines_id, lines.x AS lines_x, lines.y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
|
51
|
+
ds._fetch = {:id=>1, :x=>-1, :lines_id=>2, :lines_x=>3, :y=>4, :graph_id=>5}
|
52
|
+
ds.all.should == [{:points=>{:id=>1, :x=>-1}, :lines=>{:id=>2, :x=>3, :y=>4, :graph_id=>5}}]
|
53
|
+
|
54
|
+
ds = @ds1.select(:id.identifier, :x.qualify(:points)).graph(@ds2, :x=>:id)
|
55
|
+
ds.sql.should == 'SELECT points.id, points.x, lines.id AS lines_id, lines.x AS lines_x, lines.y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
|
56
|
+
ds._fetch = {:id=>1, :x=>-1, :lines_id=>2, :lines_x=>3, :y=>4, :graph_id=>5}
|
57
|
+
ds.all.should == [{:points=>{:id=>1, :x=>-1}, :lines=>{:id=>2, :x=>3, :y=>4, :graph_id=>5}}]
|
58
|
+
|
59
|
+
ds = @ds1.select(:id.identifier.qualify(:points), :x.identifier.as(:y)).graph(@ds2, :x=>:id)
|
60
|
+
ds.sql.should == 'SELECT points.id, points.x AS y, lines.id AS lines_id, lines.x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
|
61
|
+
ds._fetch = {:id=>1, :y=>-1, :lines_id=>2, :x=>3, :lines_y=>4, :graph_id=>5}
|
62
|
+
ds.all.should == [{:points=>{:id=>1, :y=>-1}, :lines=>{:id=>2, :x=>3, :y=>4, :graph_id=>5}}]
|
63
|
+
|
64
|
+
ds = @ds1.select(:id, :x.identifier.qualify(:points.identifier).as(:y.identifier)).graph(@ds2, :x=>:id)
|
65
|
+
ds.sql.should == 'SELECT points.id, points.x AS y, lines.id AS lines_id, lines.x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
|
66
|
+
ds._fetch = {:id=>1, :y=>-1, :lines_id=>2, :x=>3, :lines_y=>4, :graph_id=>5}
|
67
|
+
ds.all.should == [{:points=>{:id=>1, :y=>-1}, :lines=>{:id=>2, :x=>3, :y=>4, :graph_id=>5}}]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "#graph should raise error if currently selected expressions cannot be handled" do
|
71
|
+
proc{@ds1.select(1).graph(@ds2, :x=>:id)}.should raise_error(Sequel::Error)
|
72
|
+
end
|
73
|
+
|
36
74
|
it "#graph should accept a complex dataset and pass it directly to join" do
|
37
75
|
ds = @ds1.graph(@ds2.filter(:x=>1), {:x=>:id})
|
38
76
|
ds.sql.should == 'SELECT points.id, points.x, points.y, t1.id AS t1_id, t1.x AS t1_x, t1.y AS t1_y, t1.graph_id FROM points LEFT OUTER JOIN (SELECT * FROM lines WHERE (x = 1)) AS t1 ON (t1.x = points.id)'
|
@@ -5,11 +5,7 @@ describe "AssociationAutoreloading plugin" do
|
|
5
5
|
@c = Class.new(Sequel::Model)
|
6
6
|
@c.plugin :association_autoreloading
|
7
7
|
@Artist = Class.new(@c).set_dataset(:artists)
|
8
|
-
|
9
|
-
def ds1.fetch_rows(s)
|
10
|
-
(MODEL_DB.sqls ||= []) << s
|
11
|
-
yield({:id=>2, :name=>'Ar'})
|
12
|
-
end
|
8
|
+
@Artist.dataset._fetch = {:id=>2, :name=>'Ar'}
|
13
9
|
@Album = Class.new(@c).set_dataset(:albums)
|
14
10
|
@Artist.columns :id, :name
|
15
11
|
@Album.columns :id, :name, :artist_id
|
@@ -22,7 +18,6 @@ describe "AssociationAutoreloading plugin" do
|
|
22
18
|
album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
|
23
19
|
album.artist
|
24
20
|
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1']
|
25
|
-
MODEL_DB.reset
|
26
21
|
|
27
22
|
album.artist_id = 1
|
28
23
|
album.artist
|
@@ -33,7 +28,6 @@ describe "AssociationAutoreloading plugin" do
|
|
33
28
|
album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
|
34
29
|
album.artist
|
35
30
|
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1']
|
36
|
-
MODEL_DB.reset
|
37
31
|
|
38
32
|
album.artist_id = 2
|
39
33
|
album.artist
|
@@ -54,7 +48,6 @@ describe "AssociationAutoreloading plugin" do
|
|
54
48
|
album.artist_id = 1
|
55
49
|
album.artist
|
56
50
|
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
|
57
|
-
MODEL_DB.reset
|
58
51
|
|
59
52
|
album.other_artist
|
60
53
|
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
|
@@ -69,7 +62,6 @@ describe "AssociationAutoreloading plugin" do
|
|
69
62
|
album.artist_id = 1
|
70
63
|
album.composite_artist
|
71
64
|
MODEL_DB.sqls.should == ["SELECT * FROM artists WHERE ((artists.id = 1) AND (artists.name = 'Al')) LIMIT 1"]
|
72
|
-
MODEL_DB.reset
|
73
65
|
|
74
66
|
album.name = 'Al2'
|
75
67
|
album.composite_artist
|
@@ -84,7 +76,6 @@ describe "AssociationAutoreloading plugin" do
|
|
84
76
|
album = salbum.load(:id => 1, :name=>'Al', :artist_id=>2)
|
85
77
|
album.artist
|
86
78
|
MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1']
|
87
|
-
MODEL_DB.reset
|
88
79
|
|
89
80
|
album.artist_id = 1
|
90
81
|
album.artist
|