sequel 4.17.0 → 4.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +12 -0
- data/doc/dataset_filtering.rdoc +14 -14
- data/doc/release_notes/4.18.0.txt +36 -0
- data/lib/sequel/adapters/jdbc.rb +12 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -11
- data/lib/sequel/adapters/oracle.rb +1 -0
- data/lib/sequel/adapters/postgres.rb +18 -6
- data/lib/sequel/adapters/shared/db2.rb +4 -1
- data/lib/sequel/adapters/shared/mssql.rb +11 -2
- data/lib/sequel/adapters/shared/mysql.rb +4 -2
- data/lib/sequel/adapters/shared/postgres.rb +3 -6
- data/lib/sequel/adapters/shared/sqlite.rb +8 -6
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
- data/lib/sequel/database/query.rb +12 -0
- data/lib/sequel/database/schema_generator.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +1 -1
- data/lib/sequel/dataset/actions.rb +6 -4
- data/lib/sequel/model/associations.rb +1 -1
- data/lib/sequel/model/base.rb +1 -3
- data/lib/sequel/plugins/many_through_many.rb +8 -3
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +4 -4
- data/spec/adapters/postgres_spec.rb +2 -4
- data/spec/core/database_spec.rb +3 -3
- data/spec/core/dataset_spec.rb +9 -0
- data/spec/core/schema_spec.rb +21 -0
- data/spec/extensions/many_through_many_spec.rb +13 -0
- data/spec/extensions/schema_dumper_spec.rb +10 -10
- data/spec/integration/schema_test.rb +9 -0
- data/spec/model/eager_loading_spec.rb +15 -0
- metadata +62 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0fc29f94c84321473e3ed262bd8ac957a265e295
|
4
|
+
data.tar.gz: f25fc9635d509858d7275081fe1e5c67cf6db8ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 306ffd681a632fe5aee226016f51f62beb296e7b080d69b3c791690825e370c3e85ebea3002007ee9bc0f371f0d05026a215229364af10c9dcad0cc906f1e2bd
|
7
|
+
data.tar.gz: f0c9cf0fe10ce041abd556111a0f845840f2415ad6832a8ddcc2b37b0a4fcff0b538f0da3fbc95f21d7a5995df9bfb61a95bfa48a202686ba4abb4533105658d
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
=== 4.18.0 (2015-01-02)
|
2
|
+
|
3
|
+
* Make Dataset#empty? work when the dataset is ordered by a non-column expression (pete) (#923)
|
4
|
+
|
5
|
+
* Fix passing a hash value to :eager association option (jeremyevans)
|
6
|
+
|
7
|
+
* Treat all PG::ConnectionBad exceptions as disconnect errors in the postgres adapter (jeremyevans)
|
8
|
+
|
9
|
+
* Add :auto_increment key to schema information for primary key columns (jeremyevans) (#919)
|
10
|
+
|
11
|
+
* Fix handling of schema qualified tables in many_through_many associations (jeremyevans)
|
12
|
+
|
1
13
|
=== 4.17.0 (2014-12-01)
|
2
14
|
|
3
15
|
* Fix handling of Sequel::SQL::Blob instances in bound variables in the postgres adapter (jeremyevans) (#917)
|
data/doc/dataset_filtering.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Dataset Filtering
|
1
|
+
= Dataset Filtering
|
2
2
|
|
3
3
|
Sequel is very flexibile when it comes to filtering records. You can specify your conditions as a custom string, as a string with parameters, as a hash of values to compare against, or as ruby code that Sequel translates into SQL expressions.
|
4
4
|
|
@@ -76,29 +76,29 @@ If you need to select multiple items from a dataset, you can supply an array:
|
|
76
76
|
You can pass a block to where, which is evaluated in a special context:
|
77
77
|
|
78
78
|
items.where{price * 2 < 50}.sql
|
79
|
-
#=> "SELECT * FROM items WHERE ((price * 2) < 50)
|
79
|
+
#=> "SELECT * FROM items WHERE ((price * 2) < 50)
|
80
80
|
|
81
81
|
This works for the standard inequality and arithmetic operators:
|
82
82
|
|
83
83
|
items.where{price + 100 < 200}.sql
|
84
|
-
#=> "SELECT * FROM items WHERE ((price + 100) < 200)
|
84
|
+
#=> "SELECT * FROM items WHERE ((price + 100) < 200)
|
85
85
|
|
86
86
|
items.where{price - 100 > 200}.sql
|
87
|
-
#=> "SELECT * FROM items WHERE ((price - 100) > 200)
|
87
|
+
#=> "SELECT * FROM items WHERE ((price - 100) > 200)
|
88
88
|
|
89
89
|
items.where{price * 100 <= 200}.sql
|
90
|
-
#=> "SELECT * FROM items WHERE ((price * 100) <= 200)
|
90
|
+
#=> "SELECT * FROM items WHERE ((price * 100) <= 200)
|
91
91
|
|
92
92
|
items.where{price / 100 >= 200}.sql
|
93
|
-
#=> "SELECT * FROM items WHERE ((price / 100) >= 200)
|
93
|
+
#=> "SELECT * FROM items WHERE ((price / 100) >= 200)
|
94
94
|
|
95
95
|
You use the overloaded bitwise and (&) and or (|) operators to combine expressions:
|
96
96
|
|
97
97
|
items.where{(price + 100 < 200) & (price * 100 <= 200)}.sql
|
98
|
-
#=> "SELECT * FROM items WHERE (((price + 100) < 200) AND ((price * 100) <= 200))
|
98
|
+
#=> "SELECT * FROM items WHERE (((price + 100) < 200) AND ((price * 100) <= 200))
|
99
99
|
|
100
100
|
items.where{(price - 100 > 200) | (price / 100 >= 200)}.sql
|
101
|
-
#=> "SELECT * FROM items WHERE (((price - 100) > 200) OR ((price / 100) >= 200))
|
101
|
+
#=> "SELECT * FROM items WHERE (((price - 100) > 200) OR ((price / 100) >= 200))
|
102
102
|
|
103
103
|
To filter by equality, you use the standard hash, which can be combined with other expressions using Sequel.& and Sequel.|:
|
104
104
|
|
@@ -124,7 +124,7 @@ You can use the exclude method to exclude conditions:
|
|
124
124
|
#=> "SELECT * FROM items WHERE NOT active"
|
125
125
|
|
126
126
|
items.exclude{price / 100 >= 200}.sql
|
127
|
-
#=> "SELECT * FROM items WHERE ((price / 100) < 200)
|
127
|
+
#=> "SELECT * FROM items WHERE ((price / 100) < 200)
|
128
128
|
|
129
129
|
=== Comparing against column references
|
130
130
|
|
@@ -163,15 +163,15 @@ Like can also take more than one argument:
|
|
163
163
|
|
164
164
|
== String concatenation
|
165
165
|
|
166
|
-
You can concatenate SQL strings using Sequel.join:
|
166
|
+
You can concatenate SQL strings using Sequel.join:
|
167
167
|
|
168
|
-
items.where(Sequel.join([:name, :comment]).like('%
|
169
|
-
#=> "SELECT * FROM items WHERE ((name || comment) LIKE '
|
168
|
+
items.where(Sequel.join([:name, :comment]).like('Jo%nice%')).sql
|
169
|
+
#=> "SELECT * FROM items WHERE ((name || comment) LIKE 'Jo%nice%' ESCAPE '\')"
|
170
170
|
|
171
171
|
Sequel.join also takes a join argument:
|
172
172
|
|
173
|
-
items.filter(Sequel.join([:name, :comment], '
|
174
|
-
#=> "SELECT * FROM items WHERE ((name || '
|
173
|
+
items.filter(Sequel.join([:name, :comment], ':').like('John:%nice%')).sql
|
174
|
+
#=> "SELECT * FROM items WHERE ((name || ':' || comment) LIKE 'John:%nice%' ESCAPE '\')"
|
175
175
|
|
176
176
|
== Filtering using sub-queries
|
177
177
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* An :auto_increment key has been added to the schema information for
|
4
|
+
primary key columns on JDBC, PostgreSQL, MySQL, MSSQL, DB2, and
|
5
|
+
SQLite. This fixes issues in the schema_dumper extension where
|
6
|
+
non-auto-incrementing integer primary keys are no longer dumped as
|
7
|
+
auto-incrementing.
|
8
|
+
|
9
|
+
For adapters that don't have specific support for detecting
|
10
|
+
auto incrementing primary keys, Sequel now assumes a primary key
|
11
|
+
is auto incrementing only if it is not a composite primary key
|
12
|
+
and the type contains int (e.g. int, integer, bigint).
|
13
|
+
|
14
|
+
= Other Improvements
|
15
|
+
|
16
|
+
* Dataset#empty? now ignores any order on the dataset. Previously,
|
17
|
+
calling empty? on a dataset ordered by an alias in the SELECT list
|
18
|
+
could raise an exception.
|
19
|
+
|
20
|
+
* Schema qualified tables are now handled correctly in
|
21
|
+
many_through_many associations.
|
22
|
+
|
23
|
+
* Using a hash as the value for the :eager association option now
|
24
|
+
works correctly.
|
25
|
+
|
26
|
+
* All PG::ConnectionBad exceptions are now treated as disconnect
|
27
|
+
errors in the postgres adapter. This should be more robust than
|
28
|
+
the previous method of trying to recognize disconnect errors by
|
29
|
+
trying to parse the exception message.
|
30
|
+
|
31
|
+
* Sequel now skips a hash allocation when issuing queries through
|
32
|
+
datasets if sharding is not used.
|
33
|
+
|
34
|
+
* Sequel no longer uses the JDBC schema parsing in the jdbc/sqlserver
|
35
|
+
adapter. Instead, it uses the MSSQL schema parsing, which should
|
36
|
+
be more accurate than the generic JDBC schema parsing.
|
data/lib/sequel/adapters/jdbc.rb
CHANGED
@@ -604,7 +604,18 @@ module Sequel
|
|
604
604
|
schemas = []
|
605
605
|
metadata(:getColumns, nil, schema, table, nil) do |h|
|
606
606
|
next if schema_parse_table_skip?(h, schema)
|
607
|
-
s = {
|
607
|
+
s = {
|
608
|
+
:type=>schema_column_type(h[:type_name]),
|
609
|
+
:db_type=>h[:type_name],
|
610
|
+
:default=>(h[:column_def] == '' ? nil : h[:column_def]),
|
611
|
+
:allow_null=>(h[:nullable] != 0),
|
612
|
+
:primary_key=>pks.include?(h[:column_name]),
|
613
|
+
:column_size=>h[:column_size],
|
614
|
+
:scale=>h[:decimal_digits]
|
615
|
+
}
|
616
|
+
if s[:primary_key]
|
617
|
+
s[:auto_increment] = h[:is_autoincrement] == "YES"
|
618
|
+
end
|
608
619
|
s[:max_length] = s[:column_size] if s[:type] == :string
|
609
620
|
if s[:db_type] =~ DECIMAL_TYPE_RE && s[:scale] == 0
|
610
621
|
s[:type] = :integer
|
@@ -2,11 +2,6 @@ Sequel.require 'adapters/shared/mssql'
|
|
2
2
|
|
3
3
|
module Sequel
|
4
4
|
module JDBC
|
5
|
-
class Database
|
6
|
-
# Alias the generic JDBC version so it can be called directly later
|
7
|
-
alias jdbc_schema_parse_table schema_parse_table
|
8
|
-
end
|
9
|
-
|
10
5
|
# Database and Dataset instance methods for MSSQL specific
|
11
6
|
# support via JDBC.
|
12
7
|
module MSSQL
|
@@ -31,12 +26,6 @@ module Sequel
|
|
31
26
|
end
|
32
27
|
end
|
33
28
|
|
34
|
-
# Call the generic JDBC version instead of MSSQL version,
|
35
|
-
# since the JDBC version handles primary keys.
|
36
|
-
def schema_parse_table(table, opts=OPTS)
|
37
|
-
jdbc_schema_parse_table(table, opts)
|
38
|
-
end
|
39
|
-
|
40
29
|
# Primary key indexes appear to start with pk__ on MSSQL
|
41
30
|
def primary_key_index_re
|
42
31
|
PRIMARY_KEY_INDEX_RE
|
@@ -304,6 +304,7 @@ module Sequel
|
|
304
304
|
:allow_null => column.nullable?
|
305
305
|
}
|
306
306
|
h[:type] = oracle_column_type(h)
|
307
|
+
h[:auto_increment] = h[:type] == :integer if h[:primary_key]
|
307
308
|
h[:max_length] = h[:char_size] if h[:type] == :string
|
308
309
|
table_schema << [m.call(column.name), h]
|
309
310
|
end
|
@@ -108,13 +108,24 @@ module Sequel
|
|
108
108
|
# PGconn subclass for connection specific methods used with the
|
109
109
|
# pg, postgres, or postgres-pr driver.
|
110
110
|
class Adapter < ::PGconn
|
111
|
+
# The underlying exception classes to reraise as disconnect errors
|
112
|
+
# instead of regular database errors.
|
113
|
+
DISCONNECT_ERROR_CLASSES = [IOError, Errno::EPIPE, Errno::ECONNRESET]
|
114
|
+
if defined?(::PG::ConnectionBad)
|
115
|
+
DISCONNECT_ERROR_CLASSES << ::PG::ConnectionBad
|
116
|
+
end
|
117
|
+
|
111
118
|
disconnect_errors = [
|
112
119
|
'could not receive data from server',
|
113
120
|
'no connection to the server',
|
114
121
|
'connection not open',
|
115
122
|
'terminating connection due to administrator command',
|
116
|
-
'PQconsumeInput()
|
123
|
+
'PQconsumeInput() '
|
117
124
|
]
|
125
|
+
|
126
|
+
# Since exception class based disconnect checking may not work,
|
127
|
+
# also trying parsing the exception message to look for disconnect
|
128
|
+
# errors.
|
118
129
|
DISCONNECT_ERROR_RE = /\A#{Regexp.union(disconnect_errors)}/
|
119
130
|
|
120
131
|
self.translate_results = false if respond_to?(:translate_results=)
|
@@ -124,11 +135,15 @@ module Sequel
|
|
124
135
|
# are SQL strings.
|
125
136
|
attr_reader(:prepared_statements) if SEQUEL_POSTGRES_USES_PG
|
126
137
|
|
127
|
-
# Raise a Sequel::DatabaseDisconnectError if a
|
128
|
-
#
|
138
|
+
# Raise a Sequel::DatabaseDisconnectError if a one of the disconnect
|
139
|
+
# error classes is raised, or a PGError is raised and the connection
|
140
|
+
# status cannot be determined or it is not OK.
|
129
141
|
def check_disconnect_errors
|
130
142
|
begin
|
131
143
|
yield
|
144
|
+
rescue *DISCONNECT_ERROR_CLASSES => e
|
145
|
+
disconnect = true
|
146
|
+
raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError))
|
132
147
|
rescue PGError => e
|
133
148
|
disconnect = false
|
134
149
|
begin
|
@@ -140,9 +155,6 @@ module Sequel
|
|
140
155
|
disconnect ||= !status_ok
|
141
156
|
disconnect ||= e.message =~ DISCONNECT_ERROR_RE
|
142
157
|
disconnect ? raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)) : raise
|
143
|
-
rescue IOError, Errno::EPIPE, Errno::ECONNRESET => e
|
144
|
-
disconnect = true
|
145
|
-
raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError))
|
146
158
|
ensure
|
147
159
|
block if status_ok && !disconnect
|
148
160
|
end
|
@@ -40,7 +40,10 @@ module Sequel
|
|
40
40
|
column[:db_type] << "(#{column[:longlength]},#{column[:scale]})"
|
41
41
|
end
|
42
42
|
column[:allow_null] = column.delete(:nulls) == 'Y'
|
43
|
-
|
43
|
+
identity = column.delete(:identity) == 'Y'
|
44
|
+
if column[:primary_key] = identity || !column[:keyseq].nil?
|
45
|
+
column[:auto_increment] = identity
|
46
|
+
end
|
44
47
|
column[:type] = schema_column_type(column[:db_type])
|
45
48
|
column[:max_length] = column[:longlength] if column[:type] == :string
|
46
49
|
[ m.call(column.delete(:name)), column]
|
@@ -428,11 +428,15 @@ module Sequel
|
|
428
428
|
m = output_identifier_meth(opts[:dataset])
|
429
429
|
m2 = input_identifier_meth(opts[:dataset])
|
430
430
|
tn = m2.call(table_name.to_s)
|
431
|
-
table_id = get
|
431
|
+
table_id = get(Sequel.function(:object_id, tn))
|
432
432
|
info_sch_sch = opts[:information_schema_schema]
|
433
433
|
inf_sch_qual = lambda{|s| info_sch_sch ? Sequel.qualify(info_sch_sch, s) : Sequel.expr(s)}
|
434
434
|
sys_qual = lambda{|s| info_sch_sch ? Sequel.qualify(info_sch_sch, Sequel.qualify(Sequel.lit(''), s)) : Sequel.expr(s)}
|
435
435
|
|
436
|
+
identity_cols = metadata_dataset.from(:sys__columns).
|
437
|
+
where(:object_id=>table_id, :is_identity=>true).
|
438
|
+
select_map(:name)
|
439
|
+
|
436
440
|
pk_index_id = metadata_dataset.from(sys_qual.call(:sysindexes)).
|
437
441
|
where(:id=>table_id, :indid=>1..254){{(status & 2048)=>2048}}.
|
438
442
|
get(:indid)
|
@@ -440,16 +444,21 @@ module Sequel
|
|
440
444
|
join(sys_qual.call(:syscolumns).as(:sc), :id=>:id, :colid=>:colid).
|
441
445
|
where(:sik__id=>table_id, :sik__indid=>pk_index_id).
|
442
446
|
select_order_map(:sc__name)
|
447
|
+
|
443
448
|
ds = metadata_dataset.from(inf_sch_qual.call(:information_schema__tables).as(:t)).
|
444
449
|
join(inf_sch_qual.call(:information_schema__columns).as(:c), :table_catalog=>:table_catalog,
|
445
450
|
:table_schema => :table_schema, :table_name => :table_name).
|
446
451
|
select(:column_name___column, :data_type___db_type, :character_maximum_length___max_chars, :column_default___default, :is_nullable___allow_null, :numeric_precision___column_size, :numeric_scale___scale).
|
447
452
|
filter(:c__table_name=>tn)
|
453
|
+
|
448
454
|
if schema = opts[:schema]
|
449
455
|
ds.filter!(:c__table_schema=>schema)
|
450
456
|
end
|
457
|
+
|
451
458
|
ds.map do |row|
|
452
|
-
row[:primary_key] = pk_cols.include?(row[:column])
|
459
|
+
if row[:primary_key] = pk_cols.include?(row[:column])
|
460
|
+
row[:auto_increment] = identity_cols.include?(row[:column])
|
461
|
+
end
|
453
462
|
row[:allow_null] = row[:allow_null] == 'YES' ? true : false
|
454
463
|
row[:default] = nil if blank_object?(row[:default])
|
455
464
|
row[:type] = if row[:db_type] =~ DECIMAL_TYPE_RE && row[:scale] == 0
|
@@ -460,10 +460,12 @@ module Sequel
|
|
460
460
|
table = SQL::Identifier.new(im.call(table_name))
|
461
461
|
table = SQL::QualifiedIdentifier.new(im.call(opts[:schema]), table) if opts[:schema]
|
462
462
|
metadata_dataset.with_sql("DESCRIBE ?", table).map do |row|
|
463
|
-
|
463
|
+
extra = row.delete(:Extra)
|
464
|
+
if row[:primary_key] = row.delete(:Key) == 'PRI'
|
465
|
+
row[:auto_increment] = !!(extra.to_s =~ /auto_increment/io)
|
466
|
+
end
|
464
467
|
row[:allow_null] = row.delete(:Null) == 'YES'
|
465
468
|
row[:default] = row.delete(:Default)
|
466
|
-
row[:primary_key] = row.delete(:Key) == 'PRI'
|
467
469
|
row[:db_type] = row.delete(:Type)
|
468
470
|
row[:type] = schema_column_type(row[:db_type])
|
469
471
|
[m.call(row.delete(:Field)), row]
|
@@ -1035,12 +1035,6 @@ module Sequel
|
|
1035
1035
|
"ALTER TABLE #{quote_schema_table(name)} RENAME TO #{quote_identifier(schema_and_table(new_name).last)}"
|
1036
1036
|
end
|
1037
1037
|
|
1038
|
-
# PostgreSQL's autoincrementing primary keys are of type integer or bigint
|
1039
|
-
# using a nextval function call as a default.
|
1040
|
-
def schema_autoincrementing_primary_key?(schema)
|
1041
|
-
super && schema[:default] =~ /\Anextval/io
|
1042
|
-
end
|
1043
|
-
|
1044
1038
|
# Recognize PostgreSQL interval type.
|
1045
1039
|
def schema_column_type(db_type)
|
1046
1040
|
case db_type
|
@@ -1086,6 +1080,9 @@ module Sequel
|
|
1086
1080
|
row.delete(:db_base_type)
|
1087
1081
|
end
|
1088
1082
|
row[:type] = schema_column_type(row[:db_type])
|
1083
|
+
if row[:primary_key]
|
1084
|
+
row[:auto_increment] = !!(row[:default] =~ /\Anextval/io)
|
1085
|
+
end
|
1089
1086
|
[m.call(row.delete(:name)), row]
|
1090
1087
|
end
|
1091
1088
|
end
|
@@ -282,6 +282,11 @@ module Sequel
|
|
282
282
|
end
|
283
283
|
end
|
284
284
|
|
285
|
+
# SQLite does not need to specify AUTOINCREMENT, integer primary keys are automatically auto incrementing.
|
286
|
+
def auto_increment_sql
|
287
|
+
''
|
288
|
+
end
|
289
|
+
|
285
290
|
def begin_new_transaction(conn, opts)
|
286
291
|
mode = opts[:mode] || @transaction_mode
|
287
292
|
sql = TRANSACTION_MODE[mode] or raise Error, "transaction :mode must be one of: :deferred, :immediate, :exclusive, nil"
|
@@ -457,19 +462,16 @@ module Sequel
|
|
457
462
|
row.delete(:cid)
|
458
463
|
row[:allow_null] = row.delete(:notnull).to_i == 0
|
459
464
|
row[:default] = row.delete(:dflt_value)
|
460
|
-
row[:primary_key] = row.delete(:pk).to_i > 0
|
461
465
|
row[:default] = nil if blank_object?(row[:default]) || row[:default] == 'NULL'
|
462
466
|
row[:db_type] = row.delete(:type)
|
467
|
+
if row[:primary_key] = row.delete(:pk).to_i > 0
|
468
|
+
row[:auto_increment] = row[:db_type].downcase == 'integer'
|
469
|
+
end
|
463
470
|
row[:type] = schema_column_type(row[:db_type])
|
464
471
|
row
|
465
472
|
end
|
466
473
|
end
|
467
474
|
|
468
|
-
# SQLite treats integer primary keys as autoincrementing (alias of rowid).
|
469
|
-
def schema_autoincrementing_primary_key?(schema)
|
470
|
-
super && schema[:db_type].downcase == 'integer'
|
471
|
-
end
|
472
|
-
|
473
475
|
# SQLite supports schema parsing using the table_info PRAGMA, so
|
474
476
|
# parse the output of that into the format Sequel expects.
|
475
477
|
def schema_parse_table(table_name, opts)
|
@@ -1,5 +1,13 @@
|
|
1
1
|
module Sequel
|
2
2
|
module EmulateOffsetWithRowNumber
|
3
|
+
# If the offset must be emulated with ROW_NUMBER, don't remove any ordering,
|
4
|
+
# because it can cause invalid queries to be issued if an offset is required
|
5
|
+
# when ordering.
|
6
|
+
def empty?
|
7
|
+
return super unless emulate_offset_with_row_number?
|
8
|
+
get(Sequel::SQL::AliasedExpression.new(1, :one)).nil?
|
9
|
+
end
|
10
|
+
|
3
11
|
# Emulate OFFSET support with the ROW_NUMBER window function
|
4
12
|
#
|
5
13
|
# The implementation is ugly, cloning the current dataset and modifying
|
@@ -157,8 +157,20 @@ module Sequel
|
|
157
157
|
|
158
158
|
cols = schema_parse_table(table_name, opts)
|
159
159
|
raise(Error, 'schema parsing returned no columns, table probably doesn\'t exist') if cols.nil? || cols.empty?
|
160
|
+
|
161
|
+
primary_keys = 0
|
162
|
+
auto_increment_set = false
|
163
|
+
cols.all? do |_,c|
|
164
|
+
auto_increment_set = true if c.has_key?(:auto_increment)
|
165
|
+
primary_keys += 1 if c[:primary_key]
|
166
|
+
end
|
167
|
+
|
160
168
|
cols.each do |_,c|
|
161
169
|
c[:ruby_default] = column_schema_to_ruby_default(c[:default], c[:type])
|
170
|
+
if c[:primary_key] && !auto_increment_set
|
171
|
+
# If adapter didn't set it, assume that integer primary keys are auto incrementing
|
172
|
+
c[:auto_increment] = primary_keys == 1 && !!(c[:db_type] =~ /int/io)
|
173
|
+
end
|
162
174
|
if !c[:max_length] && c[:type] == :string && (max_length = column_schema_max_length(c[:db_type]))
|
163
175
|
c[:max_length] = max_length
|
164
176
|
end
|
@@ -323,7 +323,7 @@ module Sequel
|
|
323
323
|
#
|
324
324
|
# add_constraint(:valid_name, Sequel.like(:name, 'A%'))
|
325
325
|
# # ADD CONSTRAINT valid_name CHECK (name LIKE 'A%' ESCAPE '\')
|
326
|
-
# add_constraint({:name=>:valid_name, :deferrable=>true}, :
|
326
|
+
# add_constraint({:name=>:valid_name, :deferrable=>true}, Sequel.like(:name, 'A%'))
|
327
327
|
# # ADD CONSTRAINT valid_name CHECK (name LIKE 'A%' ESCAPE '\') DEFERRABLE INITIALLY DEFERRED
|
328
328
|
def add_constraint(name, *args, &block)
|
329
329
|
opts = name.is_a?(Hash) ? name : {:name=>name}
|
@@ -837,7 +837,7 @@ module Sequel
|
|
837
837
|
|
838
838
|
# Return true if the given column schema represents an autoincrementing primary key.
|
839
839
|
def schema_autoincrementing_primary_key?(schema)
|
840
|
-
!!(schema[:primary_key] && schema[:
|
840
|
+
!!(schema[:primary_key] && schema[:auto_increment])
|
841
841
|
end
|
842
842
|
|
843
843
|
# The dataset to use for proxying certain schema methods.
|
@@ -146,7 +146,8 @@ module Sequel
|
|
146
146
|
# DB[:table].empty? # SELECT 1 AS one FROM table LIMIT 1
|
147
147
|
# # => false
|
148
148
|
def empty?
|
149
|
-
|
149
|
+
ds = @opts[:order] ? unordered : self
|
150
|
+
ds.get(Sequel::SQL::AliasedExpression.new(1, :one)).nil?
|
150
151
|
end
|
151
152
|
|
152
153
|
# If a integer argument is given, it is interpreted as a limit, and then returns all
|
@@ -763,7 +764,7 @@ module Sequel
|
|
763
764
|
# DB[:table].update(:x=>nil) # UPDATE table SET x = NULL
|
764
765
|
# # => 10
|
765
766
|
#
|
766
|
-
# DB[:table].update(:x
|
767
|
+
# DB[:table].update(:x=>Sequel.expr(:x)+1, :y=>0) # UPDATE table SET x = (x + 1), y = 0
|
767
768
|
# # => 10
|
768
769
|
def update(values=OPTS, &block)
|
769
770
|
sql = update_sql(values)
|
@@ -897,13 +898,14 @@ module Sequel
|
|
897
898
|
|
898
899
|
# Set the server to use to :default unless it is already set in the passed opts
|
899
900
|
def default_server_opts(opts)
|
900
|
-
{:server=>@opts[:server] || :default}.merge(opts)
|
901
|
+
@db.sharded? ? {:server=>@opts[:server] || :default}.merge(opts) : opts
|
901
902
|
end
|
902
903
|
|
903
904
|
# Execute the given select SQL on the database using execute. Use the
|
904
905
|
# :read_only server unless a specific server is set.
|
905
906
|
def execute(sql, opts=OPTS, &block)
|
906
|
-
|
907
|
+
db = @db
|
908
|
+
db.execute(sql, db.sharded? ? {:server=>@opts[:server] || :read_only}.merge(opts) : opts, &block)
|
907
909
|
end
|
908
910
|
|
909
911
|
# Execute the given SQL on the database using execute_ddl.
|
@@ -75,7 +75,7 @@ module Sequel
|
|
75
75
|
ds = ds.order(*self[:order]) if self[:order]
|
76
76
|
ds = ds.limit(*self[:limit]) if self[:limit]
|
77
77
|
ds = ds.limit(1) if limit_to_single_row?
|
78
|
-
ds = ds.eager(
|
78
|
+
ds = ds.eager(self[:eager]) if self[:eager]
|
79
79
|
ds = ds.distinct if self[:distinct]
|
80
80
|
ds
|
81
81
|
end
|
data/lib/sequel/model/base.rb
CHANGED
@@ -1144,12 +1144,10 @@ module Sequel
|
|
1144
1144
|
alias to_hash values
|
1145
1145
|
|
1146
1146
|
# Creates new instance and passes the given values to set.
|
1147
|
-
# If a block is given, yield the instance to the block
|
1148
|
-
# from_db is true.
|
1147
|
+
# If a block is given, yield the instance to the block.
|
1149
1148
|
#
|
1150
1149
|
# Arguments:
|
1151
1150
|
# values :: should be a hash to pass to set.
|
1152
|
-
# from_db :: only for backwards compatibility, forget it exists.
|
1153
1151
|
#
|
1154
1152
|
# Artist.new(:name=>'Bob')
|
1155
1153
|
#
|
@@ -114,9 +114,14 @@ module Sequel
|
|
114
114
|
|
115
115
|
def _associated_dataset
|
116
116
|
ds = associated_class
|
117
|
-
reverse_edges
|
118
|
-
|
119
|
-
|
117
|
+
(reverse_edges + [final_reverse_edge]).each do |t|
|
118
|
+
h = {:qualify=>:deep}
|
119
|
+
if t[:alias] != t[:table]
|
120
|
+
h[:table_alias] = t[:alias]
|
121
|
+
end
|
122
|
+
ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), h)
|
123
|
+
end
|
124
|
+
ds
|
120
125
|
end
|
121
126
|
|
122
127
|
# Make sure to use unique table aliases when lazy loading or eager loading
|
data/lib/sequel/version.rb
CHANGED
@@ -3,7 +3,7 @@ module Sequel
|
|
3
3
|
MAJOR = 4
|
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 = 18
|
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
@@ -71,11 +71,11 @@ describe "MySQL", '#create_table' do
|
|
71
71
|
|
72
72
|
specify "should include an :auto_increment schema attribute if auto incrementing" do
|
73
73
|
@db.create_table(:dolls) do
|
74
|
+
primary_key :n4
|
74
75
|
Integer :n2
|
75
76
|
String :n3
|
76
|
-
Integer :n4, :auto_increment=>true, :unique=>true
|
77
77
|
end
|
78
|
-
@db.schema(:dolls).map{|k, v| v[:auto_increment]}.should == [
|
78
|
+
@db.schema(:dolls).map{|k, v| v[:auto_increment]}.should == [true, nil, nil]
|
79
79
|
end
|
80
80
|
|
81
81
|
specify "should support collate with various other column options" do
|
@@ -105,9 +105,9 @@ if [:mysql, :mysql2].include?(DB.adapter_scheme)
|
|
105
105
|
end
|
106
106
|
|
107
107
|
specify "should consider tinyint(1) datatypes as boolean if set, but not larger tinyints" do
|
108
|
-
@db.schema(:booltest, :reload=>true).
|
108
|
+
@db.schema(:booltest, :reload=>true).map{|_, s| s[:type]}.should == [:boolean, :integer]
|
109
109
|
@db.convert_tinyint_to_bool = false
|
110
|
-
@db.schema(:booltest, :reload=>true).
|
110
|
+
@db.schema(:booltest, :reload=>true).map{|_, s| s[:type]}.should == [:integer, :integer]
|
111
111
|
end
|
112
112
|
|
113
113
|
specify "should return tinyint(1)s as bools and tinyint(4)s as integers when set" do
|
@@ -252,9 +252,7 @@ describe "A PostgreSQL database" do
|
|
252
252
|
end
|
253
253
|
|
254
254
|
specify "should correctly parse the schema" do
|
255
|
-
@db.schema(:public__testfk, :reload=>true).should == [
|
256
|
-
[:id, {:type=>:integer, :ruby_default=>nil, :db_type=>"integer", :default=>"nextval('testfk_id_seq'::regclass)", :oid=>23, :primary_key=>true, :allow_null=>false}],
|
257
|
-
[:i, {:type=>:integer, :ruby_default=>nil, :db_type=>"integer", :default=>nil, :oid=>23, :primary_key=>false, :allow_null=>true}]]
|
255
|
+
@db.schema(:public__testfk, :reload=>true).map{|c,s| [c, s[:oid]]}.should == [[:id, 23], [:i, 23]]
|
258
256
|
end
|
259
257
|
|
260
258
|
specify "should parse foreign keys for tables in a schema" do
|
@@ -300,7 +298,7 @@ describe "A PostgreSQL database with domain types" do
|
|
300
298
|
specify "should correctly parse the schema" do
|
301
299
|
sch = @db.schema(:testfk, :reload=>true)
|
302
300
|
sch.first.last.delete(:domain_oid).should be_a_kind_of(Integer)
|
303
|
-
sch.should ==
|
301
|
+
sch.first.last[:db_domain_type].should == 'positive_number'
|
304
302
|
end
|
305
303
|
end
|
306
304
|
|
data/spec/core/database_spec.rb
CHANGED
@@ -2104,9 +2104,9 @@ end
|
|
2104
2104
|
describe "Database#schema_autoincrementing_primary_key?" do
|
2105
2105
|
specify "should indicate whether the parsed schema row indicates a primary key" do
|
2106
2106
|
m = Sequel::Database.new.method(:schema_autoincrementing_primary_key?)
|
2107
|
-
m.call(:primary_key=>true, :
|
2108
|
-
m.call(:primary_key=>true, :
|
2109
|
-
m.call(:primary_key=>false
|
2107
|
+
m.call(:primary_key=>true, :auto_increment=>true).should == true
|
2108
|
+
m.call(:primary_key=>true, :auto_increment=>false).should == false
|
2109
|
+
m.call(:primary_key=>false).should == false
|
2110
2110
|
end
|
2111
2111
|
end
|
2112
2112
|
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -1952,6 +1952,15 @@ describe "Dataset#empty?" do
|
|
1952
1952
|
db.from(:test).filter(false).should be_empty
|
1953
1953
|
db.sqls.should == ["SELECT 1 AS one FROM test WHERE 'f' LIMIT 1"]
|
1954
1954
|
end
|
1955
|
+
|
1956
|
+
specify "should ignore order" do
|
1957
|
+
db = Sequel.mock(:fetch=>proc{|sql| {1=>1}})
|
1958
|
+
db.from(:test).should_not be_empty
|
1959
|
+
without_order = db.sqls
|
1960
|
+
db.from(:test).order(:the_order_column).should_not be_empty
|
1961
|
+
with_order = db.sqls
|
1962
|
+
without_order.should == with_order
|
1963
|
+
end
|
1955
1964
|
end
|
1956
1965
|
|
1957
1966
|
describe "Dataset#first_source_alias" do
|
data/spec/core/schema_spec.rb
CHANGED
@@ -1544,6 +1544,27 @@ describe "Schema Parser" do
|
|
1544
1544
|
@sqls.should == ['x', 'x']
|
1545
1545
|
end
|
1546
1546
|
|
1547
|
+
specify "should set :auto_increment to true by default if unset and a single integer primary key is used" do
|
1548
|
+
meta_def(@db, :schema_parse_table){|*| [[:a, {:primary_key=>true, :db_type=>'integer'}]]}
|
1549
|
+
@db.schema(:x).first.last[:auto_increment].should == true
|
1550
|
+
end
|
1551
|
+
|
1552
|
+
specify "should not set :auto_increment if already set" do
|
1553
|
+
meta_def(@db, :schema_parse_table){|*| [[:a, {:primary_key=>true, :db_type=>'integer', :auto_increment=>false}]]}
|
1554
|
+
@db.schema(:x).first.last[:auto_increment].should == false
|
1555
|
+
end
|
1556
|
+
|
1557
|
+
specify "should set :auto_increment to false by default if unset and a single nonintegery primary key is used" do
|
1558
|
+
meta_def(@db, :schema_parse_table){|*| [[:a, {:primary_key=>true, :db_type=>'varchar'}]]}
|
1559
|
+
@db.schema(:x).first.last[:auto_increment].should == false
|
1560
|
+
end
|
1561
|
+
|
1562
|
+
specify "should set :auto_increment to false by default if unset and a composite primary key" do
|
1563
|
+
meta_def(@db, :schema_parse_table){|*| [[:a, {:primary_key=>true, :db_type=>'integer'}], [:b, {:primary_key=>true, :db_type=>'integer'}]]}
|
1564
|
+
@db.schema(:x).first.last[:auto_increment].should == false
|
1565
|
+
@db.schema(:x).last.last[:auto_increment].should == false
|
1566
|
+
end
|
1567
|
+
|
1547
1568
|
specify "should convert various types of table name arguments" do
|
1548
1569
|
meta_def(@db, :schema_parse_table) do |t, opts|
|
1549
1570
|
[[t, opts]]
|
@@ -70,6 +70,19 @@ describe Sequel::Model, "many_through_many" do
|
|
70
70
|
a.first.tags.should == [@c2.load(:id=>4)]
|
71
71
|
end
|
72
72
|
|
73
|
+
it "should handle schema qualified tables" do
|
74
|
+
@c1.many_through_many :tags, :through=>[[:myschema__albums_artists, :artist_id, :album_id], [:myschema__albums, :id, :id], [:myschema__albums_tags, :album_id, :tag_id]]
|
75
|
+
@c1.load(:id=>1).tags_dataset.sql.should == "SELECT tags.* FROM tags INNER JOIN myschema.albums_tags ON (myschema.albums_tags.tag_id = tags.id) INNER JOIN myschema.albums ON (myschema.albums.id = myschema.albums_tags.album_id) INNER JOIN myschema.albums_artists ON (myschema.albums_artists.album_id = myschema.albums.id) WHERE (myschema.albums_artists.artist_id = 1)"
|
76
|
+
|
77
|
+
@c1.dataset._fetch = {:id=>1}
|
78
|
+
@c2.dataset._fetch = {:id=>4, :x_foreign_key_x=>1}
|
79
|
+
a = @c1.eager(:tags).all
|
80
|
+
a.should == [@c1.load(:id => 1)]
|
81
|
+
DB.sqls.should == ['SELECT * FROM artists', "SELECT tags.*, myschema.albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN myschema.albums_tags ON (myschema.albums_tags.tag_id = tags.id) INNER JOIN myschema.albums ON (myschema.albums.id = myschema.albums_tags.album_id) INNER JOIN myschema.albums_artists ON (myschema.albums_artists.album_id = myschema.albums.id) WHERE (myschema.albums_artists.artist_id IN (1))"]
|
82
|
+
|
83
|
+
@c1.eager_graph(:tags).sql.should == 'SELECT artists.id, tags.id AS tags_id, tags.h1, tags.h2 FROM artists LEFT OUTER JOIN myschema.albums_artists AS albums_artists ON (albums_artists.artist_id = artists.id) LEFT OUTER JOIN myschema.albums AS albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN myschema.albums_tags AS albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id)'
|
84
|
+
end
|
85
|
+
|
73
86
|
it "should default to associating to other models in the same scope" do
|
74
87
|
begin
|
75
88
|
class ::AssociationModuleTest
|
@@ -68,7 +68,7 @@ describe "Sequel::Database dump methods" do
|
|
68
68
|
@d.meta_def(:schema) do |t, *o|
|
69
69
|
case t
|
70
70
|
when :t1, 't__t1', Sequel.identifier(:t__t1)
|
71
|
-
[[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>false}],
|
71
|
+
[[:c1, {:db_type=>'integer', :primary_key=>true, :auto_increment=>true, :allow_null=>false}],
|
72
72
|
[:c2, {:db_type=>'varchar(20)', :allow_null=>true}]]
|
73
73
|
when :t2
|
74
74
|
[[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>false}],
|
@@ -92,7 +92,7 @@ describe "Sequel::Database dump methods" do
|
|
92
92
|
end
|
93
93
|
|
94
94
|
it "should dump non-Integer primary key columns with explicit :type" do
|
95
|
-
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'bigint', :primary_key=>true, :allow_null=>true}]]}
|
95
|
+
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'bigint', :primary_key=>true, :allow_null=>true, :auto_increment=>true}]]}
|
96
96
|
@d.dump_table_schema(:t6).should == "create_table(:t6) do\n primary_key :c1, :type=>Bignum\nend"
|
97
97
|
end
|
98
98
|
|
@@ -104,7 +104,7 @@ describe "Sequel::Database dump methods" do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
it "should handle primary keys that are also foreign keys" do
|
107
|
-
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>true}]]}
|
107
|
+
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>true, :auto_increment=>true}]]}
|
108
108
|
@d.meta_def(:supports_foreign_key_parsing?){true}
|
109
109
|
@d.meta_def(:foreign_key_list){|*s| [{:columns=>[:c1], :table=>:t2, :key=>[:c2]}]}
|
110
110
|
s = @d.dump_table_schema(:t6)
|
@@ -126,7 +126,7 @@ describe "Sequel::Database dump methods" do
|
|
126
126
|
end
|
127
127
|
|
128
128
|
it "should handle foreign key options in the primary key" do
|
129
|
-
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>true}]]}
|
129
|
+
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>true, :auto_increment=>true}]]}
|
130
130
|
@d.meta_def(:supports_foreign_key_parsing?){true}
|
131
131
|
@d.meta_def(:foreign_key_list){|*s| [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_delete=>:restrict, :on_update=>:set_null, :deferrable=>true}]}
|
132
132
|
s = @d.dump_table_schema(:t6)
|
@@ -151,7 +151,7 @@ describe "Sequel::Database dump methods" do
|
|
151
151
|
end
|
152
152
|
|
153
153
|
it "should omit foreign key options that are the same as defaults in the primary key" do
|
154
|
-
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>true}]]}
|
154
|
+
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'integer', :primary_key=>true, :allow_null=>true, :auto_increment=>true}]]}
|
155
155
|
@d.meta_def(:supports_foreign_key_parsing?){true}
|
156
156
|
@d.meta_def(:foreign_key_list){|*s| [{:columns=>[:c1], :table=>:t2, :key=>[:c2], :on_delete=>:no_action, :on_update=>:no_action, :deferrable=>false}]}
|
157
157
|
s = @d.dump_table_schema(:t6)
|
@@ -232,7 +232,7 @@ END_MIG
|
|
232
232
|
it "should sort table names topologically when dumping a migration with foreign keys" do
|
233
233
|
@d.meta_def(:tables){|o| [:t1, :t2]}
|
234
234
|
@d.meta_def(:schema) do |t|
|
235
|
-
t == :t1 ? [[:c2, {:db_type=>'integer'}]] : [[:c1, {:db_type=>'integer', :primary_key=>true}]]
|
235
|
+
t == :t1 ? [[:c2, {:db_type=>'integer'}]] : [[:c1, {:db_type=>'integer', :primary_key=>true, :auto_increment=>true}]]
|
236
236
|
end
|
237
237
|
@d.meta_def(:supports_foreign_key_parsing?){true}
|
238
238
|
@d.meta_def(:foreign_key_list) do |t|
|
@@ -284,7 +284,7 @@ END_MIG
|
|
284
284
|
it "should sort topologically even if the database raises an error when trying to parse foreign keys for a non-existent table" do
|
285
285
|
@d.meta_def(:tables){|o| [:t1, :t2]}
|
286
286
|
@d.meta_def(:schema) do |t|
|
287
|
-
t == :t1 ? [[:c2, {:db_type=>'integer'}]] : [[:c1, {:db_type=>'integer', :primary_key=>true}]]
|
287
|
+
t == :t1 ? [[:c2, {:db_type=>'integer'}]] : [[:c1, {:db_type=>'integer', :primary_key=>true, :auto_increment=>true}]]
|
288
288
|
end
|
289
289
|
@d.meta_def(:supports_foreign_key_parsing?){true}
|
290
290
|
@d.meta_def(:foreign_key_list) do |t|
|
@@ -763,13 +763,13 @@ END_MIG
|
|
763
763
|
end
|
764
764
|
|
765
765
|
it "should use separate primary_key call with non autoincrementable types" do
|
766
|
-
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'varchar(8)', :primary_key=>true}]]}
|
766
|
+
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'varchar(8)', :primary_key=>true, :auto_increment=>false}]]}
|
767
767
|
@d.dump_table_schema(:t3).should == "create_table(:t3) do\n String :c1, :size=>8\n \n primary_key [:c1]\nend"
|
768
768
|
@d.dump_table_schema(:t3, :same_db=>true).should == "create_table(:t3) do\n column :c1, \"varchar(8)\"\n \n primary_key [:c1]\nend"
|
769
769
|
end
|
770
770
|
|
771
771
|
it "should use explicit type for non integer foreign_key types" do
|
772
|
-
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'date', :primary_key=>true}]]}
|
772
|
+
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'date', :primary_key=>true, :auto_increment=>false}]]}
|
773
773
|
@d.meta_def(:supports_foreign_key_parsing?){true}
|
774
774
|
@d.meta_def(:foreign_key_list){|t, *a| [{:columns=>[:c1], :table=>:t3, :key=>[:c1]}] if t == :t4}
|
775
775
|
["create_table(:t4) do\n foreign_key :c1, :t3, :type=>Date, :key=>[:c1]\n \n primary_key [:c1]\nend",
|
@@ -779,7 +779,7 @@ END_MIG
|
|
779
779
|
end
|
780
780
|
|
781
781
|
it "should correctly handing autoincrementing primary keys that are also foreign keys" do
|
782
|
-
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'integer', :primary_key=>true}]]}
|
782
|
+
@d.meta_def(:schema){|*s| [[:c1, {:db_type=>'integer', :primary_key=>true, :auto_increment=>true}]]}
|
783
783
|
@d.meta_def(:supports_foreign_key_parsing?){true}
|
784
784
|
@d.meta_def(:foreign_key_list){|t, *a| [{:columns=>[:c1], :table=>:t3, :key=>[:c1]}] if t == :t4}
|
785
785
|
["create_table(:t4) do\n primary_key :c1, :table=>:t3, :key=>[:c1]\nend",
|
@@ -88,6 +88,15 @@ describe "Database schema parser" do
|
|
88
88
|
DB.schema(:items).collect{|k,v| k if v[:primary_key]}.compact.should == [:number1, :number2]
|
89
89
|
end
|
90
90
|
|
91
|
+
cspecify "should parse autoincrementing primary keys from the schema properly", :sqlite, :oracle, :fdbsql do
|
92
|
+
DB.create_table!(:items){Integer :number}
|
93
|
+
DB.schema(:items).collect{|k,v| k if v[:primary_key] && v[:auto_increment]}.compact.should == []
|
94
|
+
DB.create_table!(:items){primary_key :number}
|
95
|
+
DB.schema(:items).collect{|k,v| k if v[:primary_key] && v[:auto_increment]}.compact.should == [:number]
|
96
|
+
DB.create_table!(:items){Integer :number, :primary_key=>true}
|
97
|
+
DB.schema(:items).collect{|k,v| k if v[:primary_key] && v[:auto_increment]}.compact.should == []
|
98
|
+
end
|
99
|
+
|
91
100
|
specify "should parse NULL/NOT NULL from the schema properly" do
|
92
101
|
DB.create_table!(:items){Integer :number, :null=>true}
|
93
102
|
DB.schema(:items).first.last[:allow_null].should == true
|
@@ -538,6 +538,21 @@ describe Sequel::Model, "#eager" do
|
|
538
538
|
DB.sqls.should == []
|
539
539
|
end
|
540
540
|
|
541
|
+
it "should respect :eager with cascaded hash when lazily loading an association" do
|
542
|
+
EagerBand.one_to_many :albums, :eager=>{:tracks=>:album}, :clone=>:albums
|
543
|
+
a = EagerBand.all
|
544
|
+
a.should == [EagerBand.load(:id=>2)]
|
545
|
+
DB.sqls.should == ['SELECT * FROM bands']
|
546
|
+
a = a.first.albums
|
547
|
+
DB.sqls.should == ['SELECT * FROM albums WHERE (albums.band_id = 2)',
|
548
|
+
'SELECT * FROM tracks WHERE (tracks.album_id IN (1))',
|
549
|
+
'SELECT * FROM albums WHERE (albums.id IN (1))']
|
550
|
+
a.should == [EagerAlbum.load(:id => 1, :band_id => 2)]
|
551
|
+
a.first.tracks.should == [EagerTrack.load(:id => 3, :album_id => 1)]
|
552
|
+
a.first.tracks.first.album.should == a.first
|
553
|
+
DB.sqls.should == []
|
554
|
+
end
|
555
|
+
|
541
556
|
it "should cascade eagerly loading when the :eager_graph association option is used" do
|
542
557
|
EagerAlbum.dataset._fetch = {:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1}
|
543
558
|
a = EagerBand.eager(:graph_albums).all
|
metadata
CHANGED
@@ -1,15 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.18.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:
|
12
|
-
dependencies:
|
11
|
+
date: 2015-01-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tzinfo
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activemodel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: nokogiri
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
13
69
|
description: The Database Toolkit for Ruby
|
14
70
|
email: code@jeremyevans.net
|
15
71
|
executables:
|
@@ -134,6 +190,7 @@ extra_rdoc_files:
|
|
134
190
|
- doc/release_notes/4.15.0.txt
|
135
191
|
- doc/release_notes/4.16.0.txt
|
136
192
|
- doc/release_notes/4.17.0.txt
|
193
|
+
- doc/release_notes/4.18.0.txt
|
137
194
|
files:
|
138
195
|
- CHANGELOG
|
139
196
|
- MIT-LICENSE
|
@@ -238,6 +295,7 @@ files:
|
|
238
295
|
- doc/release_notes/4.15.0.txt
|
239
296
|
- doc/release_notes/4.16.0.txt
|
240
297
|
- doc/release_notes/4.17.0.txt
|
298
|
+
- doc/release_notes/4.18.0.txt
|
241
299
|
- doc/release_notes/4.2.0.txt
|
242
300
|
- doc/release_notes/4.3.0.txt
|
243
301
|
- doc/release_notes/4.4.0.txt
|
@@ -736,7 +794,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
736
794
|
version: '0'
|
737
795
|
requirements: []
|
738
796
|
rubyforge_project:
|
739
|
-
rubygems_version: 2.4.
|
797
|
+
rubygems_version: 2.4.5
|
740
798
|
signing_key:
|
741
799
|
specification_version: 4
|
742
800
|
summary: The Database Toolkit for Ruby
|