sequel 4.3.0 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +34 -0
- data/README.rdoc +7 -7
- data/Rakefile +2 -2
- data/doc/active_record.rdoc +2 -2
- data/doc/association_basics.rdoc +21 -7
- data/doc/bin_sequel.rdoc +2 -2
- data/doc/cheat_sheet.rdoc +2 -1
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/migration.rdoc +2 -2
- data/doc/object_model.rdoc +2 -2
- data/doc/opening_databases.rdoc +13 -1
- data/doc/querying.rdoc +9 -4
- data/doc/release_notes/4.4.0.txt +92 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +2 -2
- data/doc/sql.rdoc +3 -3
- data/doc/thread_safety.rdoc +1 -1
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/jdbc.rb +85 -19
- data/lib/sequel/adapters/jdbc/db2.rb +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +7 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +34 -3
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +57 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -2
- data/lib/sequel/adapters/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/db2.rb +5 -0
- data/lib/sequel/adapters/shared/oracle.rb +41 -4
- data/lib/sequel/adapters/shared/sqlanywhere.rb +458 -0
- data/lib/sequel/adapters/sqlanywhere.rb +177 -0
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +11 -3
- data/lib/sequel/core.rb +4 -4
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +2 -2
- data/lib/sequel/dataset.rb +1 -1
- data/lib/sequel/dataset/actions.rb +2 -0
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +1 -1
- data/lib/sequel/dataset/query.rb +37 -16
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/date_arithmetic.rb +2 -2
- data/lib/sequel/extensions/migration.rb +1 -1
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +5 -4
- data/lib/sequel/extensions/pg_array.rb +2 -2
- data/lib/sequel/extensions/pg_array_ops.rb +2 -2
- data/lib/sequel/extensions/pg_hstore.rb +2 -2
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
- data/lib/sequel/extensions/pg_json.rb +2 -2
- data/lib/sequel/extensions/pg_json_ops.rb +2 -2
- data/lib/sequel/extensions/pg_range.rb +2 -2
- data/lib/sequel/extensions/pg_range_ops.rb +2 -2
- data/lib/sequel/extensions/pg_row.rb +2 -2
- data/lib/sequel/extensions/pg_row_ops.rb +3 -3
- data/lib/sequel/model.rb +1 -1
- data/lib/sequel/model/associations.rb +106 -17
- data/lib/sequel/model/base.rb +23 -19
- data/lib/sequel/plugins/json_serializer.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +14 -6
- data/lib/sequel/plugins/pg_array_associations.rb +28 -0
- data/lib/sequel/plugins/rcte_tree.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +11 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/table_select.rb +41 -0
- data/lib/sequel/plugins/tree.rb +1 -1
- data/lib/sequel/sql.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/oracle_spec.rb +22 -1
- data/spec/adapters/postgres_spec.rb +31 -48
- data/spec/adapters/sqlanywhere_spec.rb +170 -0
- data/spec/core/dataset_spec.rb +109 -0
- data/spec/core/object_graph_spec.rb +7 -0
- data/spec/extensions/constraint_validations_spec.rb +7 -0
- data/spec/extensions/core_refinements_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +65 -0
- data/spec/extensions/pg_array_associations_spec.rb +44 -0
- data/spec/extensions/rcte_tree_spec.rb +3 -3
- data/spec/extensions/spec_helper.rb +1 -1
- data/spec/extensions/table_select_spec.rb +71 -0
- data/spec/integration/associations_test.rb +279 -7
- data/spec/integration/dataset_test.rb +13 -4
- data/spec/integration/schema_test.rb +12 -14
- data/spec/model/associations_spec.rb +472 -3
- data/spec/model/class_dataset_methods_spec.rb +1 -0
- data/spec/model/model_spec.rb +10 -0
- metadata +10 -2
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'sqlanywhere'
|
2
|
+
|
3
|
+
Sequel.require %w'shared/sqlanywhere', 'adapters'
|
4
|
+
|
5
|
+
module Sequel
|
6
|
+
# Module for holding all SqlAnywhere-related classes and modules for Sequel.
|
7
|
+
module SqlAnywhere
|
8
|
+
|
9
|
+
class SQLAnywhereException < StandardError
|
10
|
+
attr_reader :errno
|
11
|
+
attr_reader :sql
|
12
|
+
|
13
|
+
def initialize(message, errno, sql)
|
14
|
+
super(message)
|
15
|
+
@errno = errno
|
16
|
+
@sql = sql
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
TYPE_TRANSLATOR = tt = Class.new do
|
21
|
+
def blob(s) ::Sequel::SQL::Blob.new(s) end
|
22
|
+
def boolean(s) s.to_i != 0 end
|
23
|
+
def date(s) ::Date.strptime(s) end
|
24
|
+
def decimal(s) ::BigDecimal.new(s) end
|
25
|
+
def time(s) ::Sequel.string_to_time(s) end
|
26
|
+
end.new
|
27
|
+
|
28
|
+
SQLANYWHERE_TYPES = {}
|
29
|
+
{
|
30
|
+
[0, 484] => tt.method(:decimal),
|
31
|
+
[384] => tt.method(:date),
|
32
|
+
[388] => tt.method(:time),
|
33
|
+
[500] => tt.method(:boolean),
|
34
|
+
[524, 528] => tt.method(:blob)
|
35
|
+
}.each do |k,v|
|
36
|
+
k.each{|n| SQLANYWHERE_TYPES[n] = v}
|
37
|
+
end
|
38
|
+
|
39
|
+
# Database class for SQLAnywhere databases used with Sequel.
|
40
|
+
class Database < Sequel::Database
|
41
|
+
include Sequel::SqlAnywhere::DatabaseMethods
|
42
|
+
|
43
|
+
DEFAULT_CONFIG = { :user => 'dba', :password => 'sql' }
|
44
|
+
|
45
|
+
attr_accessor :api
|
46
|
+
|
47
|
+
set_adapter_scheme :sqlanywhere
|
48
|
+
|
49
|
+
def connect(server)
|
50
|
+
opts = server_opts(server)
|
51
|
+
unless conn_string = opts[:conn_string]
|
52
|
+
conn_string = []
|
53
|
+
conn_string << "Host=#{opts[:host]}#{":#{opts[:port]}" if opts[:port]}" if opts[:host]
|
54
|
+
conn_string << "DBN=#{opts[:database]}" if opts[:database]
|
55
|
+
conn_string << "UID=#{opts[:user]}" if opts[:user]
|
56
|
+
conn_string << "Password=#{opts[:password]}" if opts[:password]
|
57
|
+
conn_string << "CommLinks=#{opts[:commlinks]}" if opts[:commlinks]
|
58
|
+
conn_string << "ConnectionName=#{opts[:connection_name]}" if opts[:connection_name]
|
59
|
+
conn_string << "CharSet=#{opts[:encoding]}" if opts[:encoding]
|
60
|
+
conn_string << "Idle=0" # Prevent the server from disconnecting us if we're idle for >240mins (by default)
|
61
|
+
conn_string << nil
|
62
|
+
conn_string = conn_string.join(';')
|
63
|
+
end
|
64
|
+
|
65
|
+
conn = @api.sqlany_new_connection
|
66
|
+
raise LoadError, "Could not connect" unless conn && @api.sqlany_connect(conn, conn_string) == 1
|
67
|
+
|
68
|
+
if Sequel.application_timezone == :utc
|
69
|
+
@api.sqlany_execute_immediate(conn, "SET TEMPORARY OPTION time_zone_adjustment=0")
|
70
|
+
end
|
71
|
+
|
72
|
+
conn
|
73
|
+
end
|
74
|
+
|
75
|
+
# Closes given database connection.
|
76
|
+
def disconnect_connection(c)
|
77
|
+
@api.sqlany_disconnect(c)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns number of rows affected
|
81
|
+
def execute_dui(sql, opts=OPTS)
|
82
|
+
synchronize do |conn|
|
83
|
+
_execute(conn, :rows, sql, opts)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def execute(sql, opts=OPTS, &block)
|
88
|
+
synchronize do |conn|
|
89
|
+
_execute(conn, :select, sql, opts, &block)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def execute_insert(sql, opts=OPTS)
|
94
|
+
synchronize do |conn|
|
95
|
+
_execute(conn, :insert, sql, opts)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
LAST_INSERT_ID = 'SELECT @@IDENTITY'.freeze
|
102
|
+
def _execute(conn, type, sql, opts)
|
103
|
+
unless rs = log_yield(sql){@api.sqlany_execute_direct(conn, sql)}
|
104
|
+
result, errstr = @api.sqlany_error(conn)
|
105
|
+
raise_error(SQLAnywhereException.new(errstr, result, sql))
|
106
|
+
end
|
107
|
+
|
108
|
+
case type
|
109
|
+
when :select
|
110
|
+
yield rs if block_given?
|
111
|
+
when :rows
|
112
|
+
return @api.sqlany_affected_rows(rs)
|
113
|
+
when :insert
|
114
|
+
_execute(conn, :select, LAST_INSERT_ID, opts){|r| return @api.sqlany_get_column(r, 0)[1] if r && @api.sqlany_fetch_next(r) == 1}
|
115
|
+
end
|
116
|
+
ensure
|
117
|
+
@api.sqlany_commit(conn) unless in_transaction?
|
118
|
+
@api.sqlany_free_stmt(rs) if rs
|
119
|
+
end
|
120
|
+
|
121
|
+
def adapter_initialize
|
122
|
+
@conversion_procs = SQLANYWHERE_TYPES.dup
|
123
|
+
@conversion_procs[392] = method(:to_application_timestamp_sa)
|
124
|
+
@api = SQLAnywhere::SQLAnywhereInterface.new
|
125
|
+
raise LoadError, "Could not load SQLAnywhere DBCAPI library" if SQLAnywhere::API.sqlany_initialize_interface(@api) == 0
|
126
|
+
raise LoadError, "Could not initialize SQLAnywhere DBCAPI library" if @api.sqlany_init == 0
|
127
|
+
end
|
128
|
+
|
129
|
+
def log_connection_execute(conn, sql)
|
130
|
+
_execute(conn, nil, sql, OPTS)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Dataset class for SqlAnywhere datasets accessed via the native driver.
|
135
|
+
class Dataset < Sequel::Dataset
|
136
|
+
include Sequel::SqlAnywhere::DatasetMethods
|
137
|
+
|
138
|
+
Database::DatasetClass = self
|
139
|
+
|
140
|
+
# Yield all rows matching this dataset. If the dataset is set to
|
141
|
+
# split multiple statements, yield arrays of hashes one per statement
|
142
|
+
# instead of yielding results for all statements as hashes.
|
143
|
+
def fetch_rows(sql)
|
144
|
+
db = @db
|
145
|
+
cps = db.conversion_procs
|
146
|
+
api = db.api
|
147
|
+
execute(sql) do |rs|
|
148
|
+
convert = (convert_smallint_to_bool and db.convert_smallint_to_bool)
|
149
|
+
col_infos = []
|
150
|
+
api.sqlany_num_cols(rs).times do |i|
|
151
|
+
_, _, name, _, type = api.sqlany_get_column_info(rs, i)
|
152
|
+
cp = if type == 500
|
153
|
+
cps[500] if convert
|
154
|
+
else
|
155
|
+
cps[type]
|
156
|
+
end
|
157
|
+
col_infos << [i, output_identifier(name), cp]
|
158
|
+
end
|
159
|
+
|
160
|
+
@columns = col_infos.map{|a| a[1]}
|
161
|
+
|
162
|
+
if rs
|
163
|
+
while api.sqlany_fetch_next(rs) == 1
|
164
|
+
h = {}
|
165
|
+
col_infos.each do |i, name, cp|
|
166
|
+
_, v = api.sqlany_get_column(rs, i)
|
167
|
+
h[name] = cp && v ? cp[v] : v
|
168
|
+
end
|
169
|
+
yield h
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
self
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -11,9 +11,12 @@ module Sequel
|
|
11
11
|
def select_sql
|
12
12
|
return super unless o = @opts[:offset]
|
13
13
|
|
14
|
-
order = @opts[:order]
|
15
|
-
if
|
16
|
-
|
14
|
+
order = @opts[:order]
|
15
|
+
if require_offset_order?
|
16
|
+
order ||= default_offset_order
|
17
|
+
if order.nil? || order.empty?
|
18
|
+
raise(Error, "#{db.database_type} requires an order be provided if using an offset")
|
19
|
+
end
|
17
20
|
end
|
18
21
|
|
19
22
|
columns = clone(:append_sql=>'').columns
|
@@ -38,5 +41,10 @@ module Sequel
|
|
38
41
|
def default_offset_order
|
39
42
|
clone(:append_sql=>'').columns
|
40
43
|
end
|
44
|
+
|
45
|
+
# Whether an order is required when using offset emulation via ROW_NUMBER, true by default.
|
46
|
+
def require_offset_order?
|
47
|
+
true
|
48
|
+
end
|
41
49
|
end
|
42
50
|
end
|
data/lib/sequel/core.rb
CHANGED
@@ -17,8 +17,8 @@
|
|
17
17
|
#
|
18
18
|
# Sequel.sqlite('blog.db'){|db| puts db[:users].count}
|
19
19
|
#
|
20
|
-
# For a more expanded introduction, see the {README}[
|
21
|
-
# For a quicker introduction, see the {cheat sheet}[
|
20
|
+
# For a more expanded introduction, see the {README}[rdoc-ref:README.rdoc].
|
21
|
+
# For a quicker introduction, see the {cheat sheet}[rdoc-ref:doc/cheat_sheet.rdoc].
|
22
22
|
module Sequel
|
23
23
|
@convert_two_digit_years = true
|
24
24
|
@datetime_class = Time
|
@@ -89,8 +89,8 @@ module Sequel
|
|
89
89
|
#
|
90
90
|
# Sequel.connect('sqlite://blog.db'){|db| puts db[:users].count}
|
91
91
|
#
|
92
|
-
# For details, see the {"Connecting to a Database" guide}[
|
93
|
-
# To set up a master/slave or sharded database connection, see the {"Master/Slave Databases and Sharding" guide}[
|
92
|
+
# For details, see the {"Connecting to a Database" guide}[rdoc-ref:doc/opening_databases.rdoc].
|
93
|
+
# To set up a master/slave or sharded database connection, see the {"Master/Slave Databases and Sharding" guide}[rdoc-ref:doc/sharding.rdoc].
|
94
94
|
def self.connect(*args, &block)
|
95
95
|
Database.connect(*args, &block)
|
96
96
|
end
|
@@ -6,7 +6,7 @@ module Sequel
|
|
6
6
|
# ---------------------
|
7
7
|
|
8
8
|
# Array of supported database adapters
|
9
|
-
ADAPTERS = %w'ado amalgalite cubrid db2 dbi do firebird ibmdb informix jdbc mock mysql mysql2 odbc openbase oracle postgres sqlite swift tinytds'.collect{|x| x.to_sym}
|
9
|
+
ADAPTERS = %w'ado amalgalite cubrid db2 dbi do firebird ibmdb informix jdbc mock mysql mysql2 odbc openbase oracle postgres sqlanywhere sqlite swift tinytds'.collect{|x| x.to_sym}
|
10
10
|
|
11
11
|
@single_threaded = false
|
12
12
|
|
@@ -6,7 +6,7 @@ module Sequel
|
|
6
6
|
# ---------------------
|
7
7
|
|
8
8
|
STRING_DEFAULT_RE = /\A'(.*)'\z/
|
9
|
-
CURRENT_TIMESTAMP_RE = /now|CURRENT|getdate|\ADate\(\)\z/io
|
9
|
+
CURRENT_TIMESTAMP_RE = /now|today|CURRENT|getdate|\ADate\(\)\z/io
|
10
10
|
COLUMN_SCHEMA_DATETIME_TYPES = [:date, :datetime]
|
11
11
|
COLUMN_SCHEMA_STRING_TYPES = [:string, :blob, :date, :datetime, :time, :enum, :set, :interval]
|
12
12
|
|
@@ -13,7 +13,7 @@ module Sequel
|
|
13
13
|
# the column method, which makes for a nicer DSL.
|
14
14
|
#
|
15
15
|
# For more information on Sequel's support for schema modification, see
|
16
|
-
# the {"Schema Modification" guide}[
|
16
|
+
# the {"Schema Modification" guide}[rdoc-ref:doc/schema_modification.rdoc].
|
17
17
|
class CreateTableGenerator
|
18
18
|
# Classes specifying generic types that Sequel will convert to database-specific types.
|
19
19
|
GENERIC_TYPES=[String, Integer, Fixnum, Bignum, Float, Numeric, BigDecimal,
|
@@ -71,7 +71,7 @@ module Sequel
|
|
71
71
|
# definitions using <tt>create_table</tt>, and +add_index+ accepts all the options
|
72
72
|
# available for index definition.
|
73
73
|
#
|
74
|
-
# See <tt>Schema::AlterTableGenerator</tt> and the {"Migrations and Schema Modification" guide}[
|
74
|
+
# See <tt>Schema::AlterTableGenerator</tt> and the {"Migrations and Schema Modification" guide}[rdoc-ref:doc/migration.rdoc].
|
75
75
|
def alter_table(name, generator=nil, &block)
|
76
76
|
generator ||= alter_table_generator(&block)
|
77
77
|
remove_cached_schema(name)
|
@@ -159,7 +159,7 @@ module Sequel
|
|
159
159
|
# :inherits :: Inherit from a different tables. An array can be
|
160
160
|
# specified to inherit from multiple tables.
|
161
161
|
#
|
162
|
-
# See <tt>Schema::Generator</tt> and the {"Schema Modification" guide}[
|
162
|
+
# See <tt>Schema::Generator</tt> and the {"Schema Modification" guide}[rdoc-ref:doc/schema_modification.rdoc].
|
163
163
|
def create_table(name, options=OPTS, &block)
|
164
164
|
remove_cached_schema(name)
|
165
165
|
options = {:generator=>options} if options.is_a?(Schema::CreateTableGenerator)
|
data/lib/sequel/dataset.rb
CHANGED
@@ -21,7 +21,7 @@ module Sequel
|
|
21
21
|
# Datasets are Enumerable objects, so they can be manipulated using any
|
22
22
|
# of the Enumerable methods, such as map, inject, etc.
|
23
23
|
#
|
24
|
-
# For more information, see the {"Dataset Basics" guide}[
|
24
|
+
# For more information, see the {"Dataset Basics" guide}[rdoc-ref:doc/dataset_basics.rdoc].
|
25
25
|
class Dataset
|
26
26
|
OPTS = Sequel::OPTS
|
27
27
|
|
@@ -271,6 +271,8 @@ module Sequel
|
|
271
271
|
# :commit_every :: Open a new transaction for every given number of records.
|
272
272
|
# For example, if you provide a value of 50, will commit
|
273
273
|
# after every 50 records.
|
274
|
+
# :return :: When the :value is :primary_key, returns an array of
|
275
|
+
# autoincremented primary key values for the rows inserted.
|
274
276
|
# :server :: Set the server/shard to use for the transaction and insert
|
275
277
|
# queries.
|
276
278
|
# :slice :: Same as :commit_every, :commit_every takes precedence.
|
data/lib/sequel/dataset/graph.rb
CHANGED
@@ -44,7 +44,7 @@ module Sequel
|
|
44
44
|
# some metadata about the join that makes it important to use +graph+ instead
|
45
45
|
# of +join_table+.
|
46
46
|
# :table_alias :: The alias to use for the table. If not specified, doesn't
|
47
|
-
# alias the table. You will get an error if the
|
47
|
+
# alias the table. You will get an error if the alias (or table) name is
|
48
48
|
# used more than once.
|
49
49
|
def graph(dataset, join_conditions = nil, options = OPTS, &block)
|
50
50
|
# Allow the use of a dataset or symbol as the first argument
|
@@ -3,7 +3,7 @@ module Sequel
|
|
3
3
|
# ---------------------
|
4
4
|
# :section: 8 - Methods related to prepared statements or bound variables
|
5
5
|
# On some adapters, these use native prepared statements and bound variables, on others
|
6
|
-
# support is emulated. For details, see the {"Prepared Statements/Bound Variables" guide}[
|
6
|
+
# support is emulated. For details, see the {"Prepared Statements/Bound Variables" guide}[rdoc-ref:doc/prepared_statements.rdoc].
|
7
7
|
# ---------------------
|
8
8
|
|
9
9
|
PREPARED_ARG_PLACEHOLDER = LiteralString.new('?').freeze
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -36,7 +36,7 @@ module Sequel
|
|
36
36
|
QUERY_METHODS = (<<-METHS).split.map{|x| x.to_sym} + JOIN_METHODS
|
37
37
|
add_graph_aliases and distinct except exclude exclude_having exclude_where
|
38
38
|
filter for_update from from_self graph grep group group_and_count group_by having intersect invert
|
39
|
-
limit lock_style naked or order order_append order_by order_more order_prepend qualify
|
39
|
+
limit lock_style naked offset or order order_append order_by order_more order_prepend qualify
|
40
40
|
reverse reverse_order select select_all select_append select_group select_more server
|
41
41
|
set_graph_aliases unfiltered ungraphed ungrouped union
|
42
42
|
unlimited unordered where with with_recursive with_sql
|
@@ -524,6 +524,7 @@ module Sequel
|
|
524
524
|
return from_self.limit(l, o) if @opts[:sql]
|
525
525
|
|
526
526
|
if l.is_a?(Range)
|
527
|
+
no_offset = false
|
527
528
|
o = l.first
|
528
529
|
l = l.last - l.first + (l.exclude_end? ? 0 : 1)
|
529
530
|
end
|
@@ -531,17 +532,10 @@ module Sequel
|
|
531
532
|
if l.is_a?(Integer)
|
532
533
|
raise(Error, 'Limits must be greater than or equal to 1') unless l >= 1
|
533
534
|
end
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
raise(Error, 'Offsets must be greater than or equal to 0') unless o >= 0
|
539
|
-
end
|
540
|
-
opts[:offset] = o
|
541
|
-
elsif !no_offset
|
542
|
-
opts[:offset] = nil
|
543
|
-
end
|
544
|
-
clone(opts)
|
535
|
+
|
536
|
+
ds = clone(:limit=>l)
|
537
|
+
ds = ds.offset(o) unless no_offset
|
538
|
+
ds
|
545
539
|
end
|
546
540
|
|
547
541
|
# Returns a cloned dataset with the given lock style. If style is a
|
@@ -568,6 +562,19 @@ module Sequel
|
|
568
562
|
ds.row_proc = nil
|
569
563
|
ds
|
570
564
|
end
|
565
|
+
|
566
|
+
# Returns a copy of the dataset with a specified order. Can be safely combined with limit.
|
567
|
+
# If you call limit with an offset, it will override override the offset if you've called
|
568
|
+
# offset first.
|
569
|
+
#
|
570
|
+
# DB[:items].offset(10) # SELECT * FROM items OFFSET 10
|
571
|
+
def offset(o)
|
572
|
+
o = o.to_i if o.is_a?(String) && !o.is_a?(LiteralString)
|
573
|
+
if o.is_a?(Integer)
|
574
|
+
raise(Error, 'Offsets must be greater than or equal to 0') unless o >= 0
|
575
|
+
end
|
576
|
+
clone(:offset => o)
|
577
|
+
end
|
571
578
|
|
572
579
|
# Adds an alternate filter to an existing filter using OR. If no filter
|
573
580
|
# exists an +Error+ is raised.
|
@@ -842,7 +849,7 @@ module Sequel
|
|
842
849
|
# where also accepts a block, which should return one of the above argument
|
843
850
|
# types, and is treated the same way. This block yields a virtual row object,
|
844
851
|
# which is easy to use to create identifiers and functions. For more details
|
845
|
-
# on the virtual row support, see the {"Virtual Rows" guide}[
|
852
|
+
# on the virtual row support, see the {"Virtual Rows" guide}[rdoc-ref:doc/virtual_rows.rdoc]
|
846
853
|
#
|
847
854
|
# If both a block and regular argument are provided, they get ANDed together.
|
848
855
|
#
|
@@ -871,7 +878,7 @@ module Sequel
|
|
871
878
|
# software = dataset.where(:category => 'software').where{price < 100}
|
872
879
|
# # SELECT * FROM items WHERE ((category = 'software') AND (price < 100))
|
873
880
|
#
|
874
|
-
# See the
|
881
|
+
# See the {"Dataset Filtering" guide}[rdoc-ref:doc/dataset_filtering.rdoc] for more examples and details.
|
875
882
|
def where(*cond, &block)
|
876
883
|
_filter(:where, *cond, &block)
|
877
884
|
end
|
@@ -961,10 +968,24 @@ module Sequel
|
|
961
968
|
!(@opts.collect{|k,v| k unless v.nil?}.compact & opts).empty?
|
962
969
|
end
|
963
970
|
|
964
|
-
# Whether this dataset is a simple
|
971
|
+
# Whether this dataset is a simple select from an underlying table, such as:
|
972
|
+
#
|
973
|
+
# SELECT * FROM table
|
974
|
+
# SELECT table.* FROM table
|
965
975
|
def simple_select_all?
|
966
976
|
o = @opts.reject{|k,v| v.nil? || NON_SQL_OPTIONS.include?(k)}
|
967
|
-
|
977
|
+
if (f = o[:from]) && f.length == 1 && (f.first.is_a?(Symbol) || f.first.is_a?(SQL::AliasedExpression))
|
978
|
+
case o.length
|
979
|
+
when 1
|
980
|
+
true
|
981
|
+
when 2
|
982
|
+
(s = o[:select]) && s.length == 1 && s.first.is_a?(SQL::ColumnAll)
|
983
|
+
else
|
984
|
+
false
|
985
|
+
end
|
986
|
+
else
|
987
|
+
false
|
988
|
+
end
|
968
989
|
end
|
969
990
|
|
970
991
|
private
|
@@ -401,10 +401,10 @@ module Sequel
|
|
401
401
|
end
|
402
402
|
|
403
403
|
ds = from(:sequel_constraint_validations)
|
404
|
-
ds.multi_insert(rows.flatten)
|
405
404
|
unless drop_rows.empty?
|
406
405
|
ds.where([:table, :constraint_name]=>drop_rows).delete
|
407
406
|
end
|
407
|
+
ds.multi_insert(rows.flatten)
|
408
408
|
end
|
409
409
|
|
410
410
|
# Add the constraint to the generator, including a NOT NULL constraint
|
@@ -91,9 +91,9 @@ module Sequel
|
|
91
91
|
each_valid_interval_unit(h, MYSQL_DURATION_UNITS) do |value, sql_unit|
|
92
92
|
expr = Sequel.function(:DATE_ADD, expr, Sequel.lit(["INTERVAL ", " "], value, sql_unit))
|
93
93
|
end
|
94
|
-
when :mssql, :h2, :access
|
94
|
+
when :mssql, :h2, :access, :sqlanywhere
|
95
95
|
units = case db_type
|
96
|
-
when :mssql
|
96
|
+
when :mssql, :sqlanywhere
|
97
97
|
MSSQL_DURATION_UNITS
|
98
98
|
when :h2
|
99
99
|
H2_DURATION_UNITS
|
@@ -373,7 +373,7 @@ module Sequel
|
|
373
373
|
migrator_class(directory).new(db, directory, opts).is_current?
|
374
374
|
end
|
375
375
|
|
376
|
-
# Migrates the supplied database using the migration files in the
|
376
|
+
# Migrates the supplied database using the migration files in the specified directory. Options:
|
377
377
|
# :allow_missing_migration_files :: Don't raise an error if there are missing migration files.
|
378
378
|
# :column :: The column in the :table argument storing the migration version (default: :version).
|
379
379
|
# :current :: The current version of the database. If not given, it is retrieved from the database
|