sequel 3.13.0 → 3.14.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +36 -0
- data/doc/release_notes/3.14.0.txt +118 -0
- data/lib/sequel/adapters/oracle.rb +7 -2
- data/lib/sequel/adapters/shared/mssql.rb +9 -3
- data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
- data/lib/sequel/connection_pool/threaded.rb +3 -3
- data/lib/sequel/database/connecting.rb +47 -11
- data/lib/sequel/database/dataset.rb +17 -6
- data/lib/sequel/database/dataset_defaults.rb +15 -3
- data/lib/sequel/database/logging.rb +4 -3
- data/lib/sequel/database/misc.rb +33 -21
- data/lib/sequel/database/query.rb +61 -22
- data/lib/sequel/database/schema_generator.rb +108 -45
- data/lib/sequel/database/schema_methods.rb +8 -5
- data/lib/sequel/dataset/actions.rb +194 -45
- data/lib/sequel/dataset/features.rb +1 -1
- data/lib/sequel/dataset/graph.rb +51 -43
- data/lib/sequel/dataset/misc.rb +29 -5
- data/lib/sequel/dataset/mutation.rb +0 -1
- data/lib/sequel/dataset/prepared_statements.rb +14 -2
- data/lib/sequel/dataset/query.rb +268 -125
- data/lib/sequel/dataset/sql.rb +33 -44
- data/lib/sequel/extensions/migration.rb +3 -2
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/model/associations.rb +89 -87
- data/lib/sequel/model/base.rb +386 -109
- data/lib/sequel/model/errors.rb +15 -1
- data/lib/sequel/model/exceptions.rb +3 -3
- data/lib/sequel/model/inflections.rb +2 -2
- data/lib/sequel/model/plugins.rb +9 -5
- data/lib/sequel/plugins/rcte_tree.rb +43 -15
- data/lib/sequel/plugins/schema.rb +6 -5
- data/lib/sequel/plugins/serialization.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/tree.rb +33 -1
- data/lib/sequel/timezones.rb +16 -10
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +36 -2
- data/spec/adapters/mysql_spec.rb +4 -4
- data/spec/adapters/postgres_spec.rb +1 -1
- data/spec/adapters/spec_helper.rb +2 -2
- data/spec/core/database_spec.rb +8 -1
- data/spec/core/dataset_spec.rb +36 -1
- data/spec/extensions/pagination_spec.rb +1 -1
- data/spec/extensions/rcte_tree_spec.rb +40 -8
- data/spec/extensions/schema_spec.rb +5 -0
- data/spec/extensions/serialization_spec.rb +4 -4
- data/spec/extensions/single_table_inheritance_spec.rb +7 -0
- data/spec/extensions/tree_spec.rb +36 -0
- data/spec/integration/dataset_test.rb +19 -0
- data/spec/integration/prepared_statement_test.rb +2 -2
- data/spec/integration/schema_test.rb +1 -1
- data/spec/integration/spec_helper.rb +4 -4
- data/spec/integration/timezone_test.rb +27 -21
- data/spec/model/associations_spec.rb +5 -5
- data/spec/model/dataset_methods_spec.rb +13 -0
- data/spec/model/hooks_spec.rb +31 -0
- data/spec/model/record_spec.rb +24 -7
- data/spec/model/validations_spec.rb +9 -4
- metadata +6 -4
@@ -58,7 +58,11 @@ module Sequel
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
# Set the method to call on identifiers going into the database
|
61
|
+
# Set the method to call on identifiers going into the database:
|
62
|
+
#
|
63
|
+
# DB[:items] # SELECT * FROM items
|
64
|
+
# DB.identifier_input_method = :upcase
|
65
|
+
# DB[:items] # SELECT * FROM ITEMS
|
62
66
|
def identifier_input_method=(v)
|
63
67
|
reset_schema_utility_dataset
|
64
68
|
@identifier_input_method = v || ""
|
@@ -77,13 +81,21 @@ module Sequel
|
|
77
81
|
end
|
78
82
|
end
|
79
83
|
|
80
|
-
# Set the method to call on identifiers coming from the database
|
84
|
+
# Set the method to call on identifiers coming from the database:
|
85
|
+
#
|
86
|
+
# DB[:items].first # {:id=>1, :name=>'foo'}
|
87
|
+
# DB.identifier_output_method = :upcase
|
88
|
+
# DB[:items].first # {:ID=>1, :NAME=>'foo'}
|
81
89
|
def identifier_output_method=(v)
|
82
90
|
reset_schema_utility_dataset
|
83
91
|
@identifier_output_method = v || ""
|
84
92
|
end
|
85
93
|
|
86
|
-
#
|
94
|
+
# Set whether to quote identifiers (columns and tables) for this database:
|
95
|
+
#
|
96
|
+
# DB[:items] # SELECT * FROM items
|
97
|
+
# DB.quote_identifiers = true
|
98
|
+
# DB[:items] # SELECT * FROM "items"
|
87
99
|
def quote_identifiers=(v)
|
88
100
|
reset_schema_utility_dataset
|
89
101
|
@quote_identifiers = v
|
@@ -9,7 +9,7 @@ module Sequel
|
|
9
9
|
# level instead of info level.
|
10
10
|
attr_accessor :log_warn_duration
|
11
11
|
|
12
|
-
# Array of SQL loggers to use for this database
|
12
|
+
# Array of SQL loggers to use for this database.
|
13
13
|
attr_accessor :loggers
|
14
14
|
|
15
15
|
# Log a message at level info to all loggers.
|
@@ -33,7 +33,9 @@ module Sequel
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
# Remove any existing loggers and just use the given logger
|
36
|
+
# Remove any existing loggers and just use the given logger:
|
37
|
+
#
|
38
|
+
# DB.logger = Logger.new($stdout)
|
37
39
|
def logger=(logger)
|
38
40
|
@loggers = Array(logger)
|
39
41
|
end
|
@@ -57,6 +59,5 @@ module Sequel
|
|
57
59
|
def log_each(level, message)
|
58
60
|
@loggers.each{|logger| logger.send(level, message)}
|
59
61
|
end
|
60
|
-
|
61
62
|
end
|
62
63
|
end
|
data/lib/sequel/database/misc.rb
CHANGED
@@ -16,24 +16,24 @@ module Sequel
|
|
16
16
|
end
|
17
17
|
private_class_method :uri_to_options
|
18
18
|
|
19
|
-
# The options for this database
|
19
|
+
# The options hash for this database
|
20
20
|
attr_reader :opts
|
21
21
|
|
22
22
|
# Constructs a new instance of a database connection with the specified
|
23
23
|
# options hash.
|
24
24
|
#
|
25
|
-
#
|
25
|
+
# Accepts the following options:
|
26
|
+
# :default_schema :: The default schema to use, should generally be nil
|
27
|
+
# :disconnection_proc :: A proc used to disconnect the connection
|
28
|
+
# :identifier_input_method :: A string method symbol to call on identifiers going into the database
|
29
|
+
# :identifier_output_method :: A string method symbol to call on identifiers coming from the database
|
30
|
+
# :logger :: A specific logger to use
|
31
|
+
# :loggers :: An array of loggers to use
|
32
|
+
# :quote_identifiers :: Whether to quote identifiers
|
33
|
+
# :servers :: A hash specifying a server/shard specific options, keyed by shard symbol
|
34
|
+
# :single_threaded :: Whether to use a single-threaded connection pool
|
26
35
|
#
|
27
|
-
#
|
28
|
-
# * :default_schema : The default schema to use, should generally be nil
|
29
|
-
# * :disconnection_proc: A proc used to disconnect the connection.
|
30
|
-
# * :identifier_input_method: A string method symbol to call on identifiers going into the database
|
31
|
-
# * :identifier_output_method: A string method symbol to call on identifiers coming from the database
|
32
|
-
# * :loggers : An array of loggers to use.
|
33
|
-
# * :quote_identifiers : Whether to quote identifiers
|
34
|
-
# * :single_threaded : Whether to use a single-threaded connection pool
|
35
|
-
#
|
36
|
-
# All options given are also passed to the ConnectionPool. If a block
|
36
|
+
# All options given are also passed to the connection pool. If a block
|
37
37
|
# is given, it is used as the connection_proc for the ConnectionPool.
|
38
38
|
def initialize(opts = {}, &block)
|
39
39
|
@opts ||= opts
|
@@ -58,6 +58,9 @@ module Sequel
|
|
58
58
|
end
|
59
59
|
|
60
60
|
# Cast the given type to a literal type
|
61
|
+
#
|
62
|
+
# DB.cast_type_literal(Float) # double precision
|
63
|
+
# DB.cast_type_literal(:foo) # foo
|
61
64
|
def cast_type_literal(type)
|
62
65
|
type_literal(:type=>type)
|
63
66
|
end
|
@@ -69,28 +72,33 @@ module Sequel
|
|
69
72
|
"#<#{self.class}: #{(uri rescue opts).inspect}>"
|
70
73
|
end
|
71
74
|
|
72
|
-
# Proxy the literal call to the dataset
|
75
|
+
# Proxy the literal call to the dataset.
|
76
|
+
#
|
77
|
+
# DB.literal(1) # 1
|
78
|
+
# DB.literal(:a) # a
|
79
|
+
# DB.literal('a') # 'a'
|
73
80
|
def literal(v)
|
74
81
|
schema_utility_dataset.literal(v)
|
75
82
|
end
|
76
83
|
|
77
|
-
# Default serial primary key options
|
84
|
+
# Default serial primary key options, used by the table creation
|
85
|
+
# code.
|
78
86
|
def serial_primary_key_options
|
79
87
|
{:primary_key => true, :type => Integer, :auto_increment => true}
|
80
88
|
end
|
81
89
|
|
82
90
|
# Whether the database and adapter support prepared transactions
|
83
|
-
# (two-phase commit), false by default
|
91
|
+
# (two-phase commit), false by default.
|
84
92
|
def supports_prepared_transactions?
|
85
93
|
false
|
86
94
|
end
|
87
95
|
|
88
|
-
# Whether the database and adapter support savepoints, false by default
|
96
|
+
# Whether the database and adapter support savepoints, false by default.
|
89
97
|
def supports_savepoints?
|
90
98
|
false
|
91
99
|
end
|
92
100
|
|
93
|
-
# Whether the database and adapter support transaction isolation levels, false by default
|
101
|
+
# Whether the database and adapter support transaction isolation levels, false by default.
|
94
102
|
def supports_transaction_isolation_levels?
|
95
103
|
false
|
96
104
|
end
|
@@ -110,12 +118,17 @@ module Sequel
|
|
110
118
|
end
|
111
119
|
end
|
112
120
|
|
113
|
-
# Returns the URI identifying the database
|
121
|
+
# Returns the URI identifying the database, which may not be the
|
122
|
+
# same as the URI used when connecting.
|
114
123
|
# This method can raise an error if the database used options
|
115
|
-
# instead of a connection string
|
124
|
+
# instead of a connection string, and will not include uri
|
125
|
+
# parameters.
|
126
|
+
#
|
127
|
+
# Sequel.connect('postgres://localhost/db?user=billg').url
|
128
|
+
# # => "postgres://billg@localhost/db"
|
116
129
|
def uri
|
117
130
|
uri = URI::Generic.new(
|
118
|
-
|
131
|
+
adapter_scheme.to_s,
|
119
132
|
nil,
|
120
133
|
@opts[:host],
|
121
134
|
@opts[:port],
|
@@ -203,7 +216,6 @@ module Sequel
|
|
203
216
|
|
204
217
|
# Typecast the value to a DateTime or Time depending on Sequel.datetime_class
|
205
218
|
def typecast_value_datetime(value)
|
206
|
-
raise(Sequel::InvalidValue, "invalid value for Datetime: #{value.inspect}") unless [DateTime, Date, Time, String, Hash].any?{|c| value.is_a?(c)}
|
207
219
|
klass = Sequel.datetime_class
|
208
220
|
if value.is_a?(Hash)
|
209
221
|
klass.send(klass == Time ? :mktime : :new, *[:year, :month, :day, :hour, :minute, :second].map{|x| (value[x] || value[x.to_s]).to_i})
|
@@ -26,7 +26,7 @@ module Sequel
|
|
26
26
|
MYSQL_TIMESTAMP_RE = /\ACURRENT_(?:DATE|TIMESTAMP)?\z/
|
27
27
|
STRING_DEFAULT_RE = /\A'(.*)'\z/
|
28
28
|
|
29
|
-
# The prepared statement
|
29
|
+
# The prepared statement object hash for this database, keyed by name symbol
|
30
30
|
attr_reader :prepared_statements
|
31
31
|
|
32
32
|
# The default transaction isolation level for this database,
|
@@ -44,6 +44,9 @@ module Sequel
|
|
44
44
|
|
45
45
|
# Call the prepared statement with the given name with the given hash
|
46
46
|
# of arguments.
|
47
|
+
#
|
48
|
+
# DB[:items].filter(:id=>1).prepare(:first, :sa)
|
49
|
+
# DB.call(:sa) # SELECT * FROM items WHERE id = 1
|
47
50
|
def call(ps_name, hash={})
|
48
51
|
prepared_statements[ps_name].call(hash)
|
49
52
|
end
|
@@ -55,7 +58,7 @@ module Sequel
|
|
55
58
|
end
|
56
59
|
|
57
60
|
# Method that should be used when submitting any DDL (Data Definition
|
58
|
-
# Language) SQL
|
61
|
+
# Language) SQL, such as +create_table+. By default, calls +execute_dui+.
|
59
62
|
# This method should not be called directly by user code.
|
60
63
|
def execute_ddl(sql, opts={}, &block)
|
61
64
|
execute_dui(sql, opts, &block)
|
@@ -77,11 +80,9 @@ module Sequel
|
|
77
80
|
|
78
81
|
# Returns a single value from the database, e.g.:
|
79
82
|
#
|
80
|
-
# # SELECT 1
|
81
|
-
#
|
82
|
-
#
|
83
|
-
# # SELECT version()
|
84
|
-
# DB.get(:version.sql_function) #=> ...
|
83
|
+
# DB.get(1) # SELECT 1
|
84
|
+
# # => 1
|
85
|
+
# DB.get{version{}} # SELECT server_version()
|
85
86
|
def get(*args, &block)
|
86
87
|
dataset.get(*args, &block)
|
87
88
|
end
|
@@ -92,13 +93,18 @@ module Sequel
|
|
92
93
|
# depending on if the index is unique.
|
93
94
|
#
|
94
95
|
# Should not include the primary key index, functional indexes, or partial indexes.
|
96
|
+
#
|
97
|
+
# DB.indexes(:artists)
|
98
|
+
# # => {:artists_name_ukey=>{:columns=>[:name], :unique=>true}}
|
95
99
|
def indexes(table, opts={})
|
96
100
|
raise NotImplemented, "#indexes should be overridden by adapters"
|
97
101
|
end
|
98
102
|
|
99
103
|
# Runs the supplied SQL statement string on the database server. Returns nil.
|
100
104
|
# Options:
|
101
|
-
#
|
105
|
+
# :server :: The server to run the SQL on.
|
106
|
+
#
|
107
|
+
# DB.run("SET some_server_variable = 42")
|
102
108
|
def run(sql, opts={})
|
103
109
|
execute_ddl(sql, opts)
|
104
110
|
nil
|
@@ -109,13 +115,40 @@ module Sequel
|
|
109
115
|
# the first member being the column name, and the second member being a hash of column information.
|
110
116
|
# Available options are:
|
111
117
|
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
118
|
+
# :reload :: Ignore any cached results, and get fresh information from the database.
|
119
|
+
# :schema :: An explicit schema to use. It may also be implicitly provided
|
120
|
+
# via the table name.
|
121
|
+
#
|
122
|
+
# If schema parsing is supported by the database, the column information should at least contain the
|
123
|
+
# following columns:
|
124
|
+
#
|
125
|
+
# :allow_null :: Whether NULL is an allowed value for the column.
|
126
|
+
# :db_type :: The database type for the column, as a database specific string.
|
127
|
+
# :default :: The database default for the column, as a database specific string.
|
128
|
+
# :primary_key :: Whether the columns is a primary key column. If this column is not present,
|
129
|
+
# it means that primary key information is unavailable, not that the column
|
130
|
+
# is not a primary key.
|
131
|
+
# :ruby_default :: The database default for the column, as a ruby object. In many cases, complex
|
132
|
+
# database defaults cannot be parsed into ruby objects.
|
133
|
+
# :type :: A symbol specifying the type, such as :integer or :string.
|
134
|
+
#
|
135
|
+
# Example:
|
136
|
+
#
|
137
|
+
# DB.schema(:artists)
|
138
|
+
# # [[:id,
|
139
|
+
# # {:type=>:integer,
|
140
|
+
# # :primary_key=>true,
|
141
|
+
# # :default=>"nextval('artist_id_seq'::regclass)",
|
142
|
+
# # :ruby_default=>nil,
|
143
|
+
# # :db_type=>"integer",
|
144
|
+
# # :allow_null=>false}],
|
145
|
+
# # [:name,
|
146
|
+
# # {:type=>:string,
|
147
|
+
# # :primary_key=>false,
|
148
|
+
# # :default=>nil,
|
149
|
+
# # :ruby_default=>nil,
|
150
|
+
# # :db_type=>"text",
|
151
|
+
# # :allow_null=>false}]]
|
119
152
|
def schema(table, opts={})
|
120
153
|
raise(Error, 'schema parsing is not implemented on this database') unless respond_to?(:schema_parse_table, true)
|
121
154
|
|
@@ -134,6 +167,8 @@ module Sequel
|
|
134
167
|
|
135
168
|
# Returns true if a table with the given name exists. This requires a query
|
136
169
|
# to the database.
|
170
|
+
#
|
171
|
+
# DB.table_exists?(:foo) # => false
|
137
172
|
def table_exists?(name)
|
138
173
|
begin
|
139
174
|
from(name).first
|
@@ -144,6 +179,8 @@ module Sequel
|
|
144
179
|
end
|
145
180
|
|
146
181
|
# Return all tables in the database as an array of symbols.
|
182
|
+
#
|
183
|
+
# DB.tables # => [:albums, :artists]
|
147
184
|
def tables(opts={})
|
148
185
|
raise NotImplemented, "#tables should be overridden by adapters"
|
149
186
|
end
|
@@ -155,13 +192,15 @@ module Sequel
|
|
155
192
|
# The following options are respected:
|
156
193
|
#
|
157
194
|
# :isolation :: The transaction isolation level to use for this transaction,
|
158
|
-
# should be :uncommitted, :committed, :repeatable, or :serializable
|
195
|
+
# should be :uncommitted, :committed, :repeatable, or :serializable,
|
196
|
+
# used if given and the database/adapter supports customizable
|
197
|
+
# transaction isolation levels.
|
159
198
|
# :prepare :: A string to use as the transaction identifier for a
|
160
199
|
# prepared transaction (two-phase commit), if the database/adapter
|
161
|
-
# supports prepared transactions
|
162
|
-
# :server :: The server to use for the transaction
|
200
|
+
# supports prepared transactions.
|
201
|
+
# :server :: The server to use for the transaction.
|
163
202
|
# :savepoint :: Whether to create a new savepoint for this transaction,
|
164
|
-
# only respected if the database
|
203
|
+
# only respected if the database/adapter supports savepoints. By
|
165
204
|
# default Sequel will reuse an existing transaction, so if you want to
|
166
205
|
# use a savepoint you must use this option.
|
167
206
|
def transaction(opts={}, &block)
|
@@ -175,7 +214,7 @@ module Sequel
|
|
175
214
|
|
176
215
|
# Internal generic transaction method. Any exception raised by the given
|
177
216
|
# block will cause the transaction to be rolled back. If the exception is
|
178
|
-
# not Sequel::Rollback, the error will be reraised. If no exception occurs
|
217
|
+
# not a Sequel::Rollback, the error will be reraised. If no exception occurs
|
179
218
|
# inside the block, the transaction is commited.
|
180
219
|
def _transaction(conn, opts={})
|
181
220
|
begin
|
@@ -379,8 +418,8 @@ module Sequel
|
|
379
418
|
end
|
380
419
|
|
381
420
|
# Match the database's column type to a ruby type via a
|
382
|
-
# regular expression
|
383
|
-
#
|
421
|
+
# regular expression, and return the ruby type as a symbol
|
422
|
+
# such as :integer or :string.
|
384
423
|
def schema_column_type(db_type)
|
385
424
|
case db_type
|
386
425
|
when /\Ainterval\z/io
|
@@ -19,13 +19,13 @@ module Sequel
|
|
19
19
|
GENERIC_TYPES=[String, Integer, Fixnum, Bignum, Float, Numeric, BigDecimal,
|
20
20
|
Date, DateTime, Time, File, TrueClass, FalseClass]
|
21
21
|
|
22
|
-
# Return the
|
22
|
+
# Return the column hashes created by this generator
|
23
23
|
attr_reader :columns
|
24
24
|
|
25
|
-
# Return the
|
25
|
+
# Return the constraint hashes created by this generator
|
26
26
|
attr_reader :constraints
|
27
27
|
|
28
|
-
# Return the
|
28
|
+
# Return the index hashes created by this generator
|
29
29
|
attr_reader :indexes
|
30
30
|
|
31
31
|
# Set the database in which to create the table, and evaluate the block
|
@@ -50,14 +50,26 @@ module Sequel
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
# Add
|
54
|
-
# or args
|
53
|
+
# Add an unnamed constraint to the DDL, specified by the given block
|
54
|
+
# or args:
|
55
|
+
#
|
56
|
+
# check(:num=>1..5) # CHECK num >= 1 AND num <= 5
|
57
|
+
# check{num > 5} # CHECK num > 5
|
55
58
|
def check(*args, &block)
|
56
59
|
constraint(nil, *args, &block)
|
57
60
|
end
|
58
61
|
|
59
62
|
# Add a column with the given name, type, and opts to the DDL.
|
60
63
|
#
|
64
|
+
# column :num, :integer
|
65
|
+
# # num INTEGER
|
66
|
+
#
|
67
|
+
# column :name, String, :null=>false, :default=>'a'
|
68
|
+
# # name varchar(255) NOT NULL DEFAULT 'a'
|
69
|
+
#
|
70
|
+
# inet :ip
|
71
|
+
# # ip inet
|
72
|
+
#
|
61
73
|
# You can also create columns via method missing, so the following are
|
62
74
|
# equivalent:
|
63
75
|
#
|
@@ -66,30 +78,32 @@ module Sequel
|
|
66
78
|
#
|
67
79
|
# The following options are supported:
|
68
80
|
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
81
|
+
# :default :: The default value for the column.
|
82
|
+
# :deferrable :: This ensure Referential Integrity will work even if
|
83
|
+
# reference table will use for its foreign key a value that does not
|
84
|
+
# exists(yet) on referenced table. Basically it adds
|
85
|
+
# DEFERRABLE INITIALLY DEFERRED on key creation.
|
86
|
+
# :index :: Create an index on this column.
|
87
|
+
# :key :: For foreign key columns, the column in the associated table
|
88
|
+
# that this column references. Unnecessary if this column
|
89
|
+
# references the primary key of the associated table.
|
90
|
+
# :null :: Mark the column as allowing NULL values (if true),
|
91
|
+
# or not allowing NULL values (if false). If unspecified, will default
|
92
|
+
# to whatever the database default is.
|
93
|
+
# :on_delete :: Specify the behavior of this column when being deleted
|
94
|
+
# (:restrict, cascade, :set_null, :set_default, :no_action).
|
95
|
+
# :on_update :: Specify the behavior of this column when being updated
|
96
|
+
# (:restrict, cascade, :set_null, :set_default, :no_action).
|
97
|
+
# :primary_key :: Make the column as a single primary key column. This should only
|
98
|
+
# be used if you have a single, nonautoincrementing primary key column.
|
99
|
+
# :size :: The size of the column, generally used with string
|
100
|
+
# columns to specify the maximum number of characters the column will hold.
|
101
|
+
# An array of two integers can be provided to set the size and the
|
102
|
+
# precision, respectively, of decimal columns.
|
103
|
+
# :unique :: Mark the column as unique, generally has the same effect as
|
104
|
+
# creating a unique index on the column.
|
105
|
+
# :unsigned :: Make the column type unsigned, only useful for integer
|
106
|
+
# columns.
|
93
107
|
def column(name, type, opts = {})
|
94
108
|
columns << {:name => name, :type => type}.merge(opts)
|
95
109
|
index(name) if opts[:index]
|
@@ -97,12 +111,19 @@ module Sequel
|
|
97
111
|
|
98
112
|
# Adds a named constraint (or unnamed if name is nil) to the DDL,
|
99
113
|
# with the given block or args.
|
114
|
+
#
|
115
|
+
# constraint(:blah, :num=>1..5) # CONSTRAINT blah CHECK num >= 1 AND num <= 5
|
116
|
+
# check(:foo){num > 5} # CONSTRAINT foo CHECK num > 5
|
100
117
|
def constraint(name, *args, &block)
|
101
118
|
constraints << {:name => name, :type => :check, :check => block || args}
|
102
119
|
end
|
103
120
|
|
104
121
|
# Add a foreign key in the table that references another table to the DDL. See column
|
105
122
|
# for available options.
|
123
|
+
#
|
124
|
+
# foreign_key(:artist_id) # artist_id INTEGER
|
125
|
+
# foreign_key(:artist_id, :artists) # artist_id INTEGER REFERENCES artists
|
126
|
+
# foreign_key(:artist_id, :artists, :key=>:id) # artist_id INTEGER REFERENCES artists(id)
|
106
127
|
def foreign_key(name, table=nil, opts = {})
|
107
128
|
opts = case table
|
108
129
|
when Hash
|
@@ -131,31 +152,38 @@ module Sequel
|
|
131
152
|
# Add an index on the given column(s) with the given options to the DDL.
|
132
153
|
# The available options are:
|
133
154
|
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
155
|
+
# :type :: The type of index to use (only supported by some databases)
|
156
|
+
# :unique :: Make the index unique, so duplicate values are not allowed.
|
157
|
+
# :where :: Create a partial index (only supported by some databases)
|
158
|
+
#
|
159
|
+
# index :name
|
160
|
+
# # CREATE INDEX table_name_index ON table (name)
|
161
|
+
#
|
162
|
+
# index [:artist_id, :name]
|
163
|
+
# # CREATE INDEX table_artist_id_name_index ON table (artist_id, name)
|
137
164
|
def index(columns, opts = {})
|
138
165
|
indexes << {:columns => Array(columns)}.merge(opts)
|
139
166
|
end
|
140
167
|
|
141
|
-
# Add a column with the given type, name, and opts to the DDL. See column for available
|
168
|
+
# Add a column with the given type, name, and opts to the DDL. See +column+ for available
|
142
169
|
# options.
|
143
170
|
def method_missing(type, name = nil, opts = {})
|
144
171
|
name ? column(name, type, opts) : super
|
145
172
|
end
|
146
173
|
|
147
|
-
#
|
148
|
-
#
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
174
|
+
# Adds an autoincrementing primary key column or a primary key constraint to the DDL.
|
175
|
+
# To create a constraint, the first argument should be an array of column symbols
|
176
|
+
# specifying the primary key columns. To create an autoincrementing primary key
|
177
|
+
# column, a single symbol can be used. In both cases, an options hash can be used
|
178
|
+
# as the second argument.
|
179
|
+
#
|
180
|
+
# If you want to create a primary key column that is not autoincrementing, you
|
181
|
+
# should not use this method. Instead, you should use the regular +column+ method
|
182
|
+
# with a <tt>:primary_key=>true</tt> option.
|
153
183
|
#
|
154
184
|
# Examples:
|
155
185
|
# primary_key(:id)
|
156
|
-
# primary_key(:zip_code, :null => false)
|
157
186
|
# primary_key([:street_number, :house_number])
|
158
|
-
# primary_key(:id, :string, :auto_increment => false)
|
159
187
|
def primary_key(name, *args)
|
160
188
|
return composite_primary_key(name, *args) if name.is_a?(Array)
|
161
189
|
@primary_key = @db.serial_primary_key_options.merge({:name => name})
|
@@ -170,7 +198,7 @@ module Sequel
|
|
170
198
|
@primary_key
|
171
199
|
end
|
172
200
|
|
173
|
-
# The name of the primary key for this
|
201
|
+
# The name of the primary key for this generator, if it has a primary key.
|
174
202
|
def primary_key_name
|
175
203
|
@primary_key[:name] if @primary_key
|
176
204
|
end
|
@@ -181,6 +209,8 @@ module Sequel
|
|
181
209
|
end
|
182
210
|
|
183
211
|
# Add a unique constraint on the given columns to the DDL.
|
212
|
+
#
|
213
|
+
# unique(:name) # UNIQUE (name)
|
184
214
|
def unique(columns, opts = {})
|
185
215
|
constraints << {:type => :unique, :columns => Array(columns)}.merge(opts)
|
186
216
|
end
|
@@ -205,7 +235,7 @@ module Sequel
|
|
205
235
|
# to instantiate directly. Instances are created by Database#alter_table.
|
206
236
|
# It is used to specify table alteration parameters. It takes a Database
|
207
237
|
# object and a block of operations to perform on the table, and
|
208
|
-
# gives the Database
|
238
|
+
# gives the Database an array of table altering operations, which the database uses to
|
209
239
|
# alter a table's description.
|
210
240
|
#
|
211
241
|
# For more information on Sequel's support for schema modification, see
|
@@ -224,17 +254,25 @@ module Sequel
|
|
224
254
|
|
225
255
|
# Add a column with the given name, type, and opts to the DDL for the table.
|
226
256
|
# See Generator#column for the available options.
|
257
|
+
#
|
258
|
+
# add_column(:name, String) # ADD COLUMN name varchar(255)
|
227
259
|
def add_column(name, type, opts = {})
|
228
260
|
@operations << {:op => :add_column, :name => name, :type => type}.merge(opts)
|
229
261
|
end
|
230
262
|
|
231
263
|
# Add a constraint with the given name and args to the DDL for the table.
|
232
264
|
# See Generator#constraint.
|
265
|
+
#
|
266
|
+
# add_constraint(:valid_name, :name.like('A%'))
|
267
|
+
# # ADD CONSTRAINT valid_name CHECK (name LIKE 'A%')
|
233
268
|
def add_constraint(name, *args, &block)
|
234
269
|
@operations << {:op => :add_constraint, :name => name, :type => :check, :check => block || args}
|
235
270
|
end
|
236
271
|
|
237
272
|
# Add a unique constraint to the given column(s)
|
273
|
+
#
|
274
|
+
# add_unique_constraint(:name) # ADD UNIQUE (name)
|
275
|
+
# add_unique_constraint(:name, :name=>:unique_name) # ADD CONSTRAINT unique_name UNIQUE (name)
|
238
276
|
def add_unique_constraint(columns, opts = {})
|
239
277
|
@operations << {:op => :add_constraint, :type => :unique, :columns => Array(columns)}.merge(opts)
|
240
278
|
end
|
@@ -246,8 +284,11 @@ module Sequel
|
|
246
284
|
# keys. In this case, it will assume the columns exists and will only add
|
247
285
|
# the constraint.
|
248
286
|
#
|
249
|
-
# NOTE: If you need to add a foreign key constraint to
|
287
|
+
# NOTE: If you need to add a foreign key constraint to a single existing column
|
250
288
|
# use the composite key syntax even if it is only one column.
|
289
|
+
#
|
290
|
+
# add_foreign_key(:artist_id, :table) # ADD COLUMN artist_id integer REFERENCES table
|
291
|
+
# add_foreign_key([:name], :table) # ADD FOREIGN KEY (name) REFERENCES table
|
251
292
|
def add_foreign_key(name, table, opts = {})
|
252
293
|
return add_composite_foreign_key(name, table, opts) if name.is_a?(Array)
|
253
294
|
add_column(name, Integer, {:table=>table}.merge(opts))
|
@@ -261,12 +302,18 @@ module Sequel
|
|
261
302
|
|
262
303
|
# Add an index on the given columns to the DDL for the table. See
|
263
304
|
# Generator#index for available options.
|
305
|
+
#
|
306
|
+
# add_index(:artist_id) # CREATE INDEX table_artist_id_index ON table (artist_id)
|
264
307
|
def add_index(columns, opts = {})
|
265
308
|
@operations << {:op => :add_index, :columns => Array(columns)}.merge(opts)
|
266
309
|
end
|
267
310
|
|
268
311
|
# Add a primary key to the DDL for the table. See Generator#column
|
269
|
-
# for the available options.
|
312
|
+
# for the available options. Like +add_foreign_key+, if you specify
|
313
|
+
# the column name as an array, it just creates a constraint:
|
314
|
+
#
|
315
|
+
# add_primary_key(:id) # ADD COLUMN id serial PRIMARY KEY
|
316
|
+
# add_primary_key([:artist_id, :name]) # ADD PRIMARY KEY (artist_id, name)
|
270
317
|
def add_primary_key(name, opts = {})
|
271
318
|
return add_composite_primary_key(name, opts) if name.is_a?(Array)
|
272
319
|
opts = @db.serial_primary_key_options.merge(opts)
|
@@ -280,36 +327,52 @@ module Sequel
|
|
280
327
|
end
|
281
328
|
|
282
329
|
# Remove a column from the DDL for the table.
|
330
|
+
#
|
331
|
+
# drop_column(:artist_id) # DROP COLUMN artist_id
|
283
332
|
def drop_column(name)
|
284
333
|
@operations << {:op => :drop_column, :name => name}
|
285
334
|
end
|
286
335
|
|
287
336
|
# Remove a constraint from the DDL for the table.
|
337
|
+
#
|
338
|
+
# drop_constraint(:unique_name) # DROP CONSTRAINT unique_name
|
288
339
|
def drop_constraint(name)
|
289
340
|
@operations << {:op => :drop_constraint, :name => name}
|
290
341
|
end
|
291
342
|
|
292
343
|
# Remove an index from the DDL for the table.
|
344
|
+
#
|
345
|
+
# drop_index(:artist_id) # DROP INDEX table_artist_id_index
|
346
|
+
# drop_index([:a, :b]) # DROP INDEX table_a_b_index
|
347
|
+
# drop_index([:a, :b], :name=>:foo) # DROP INDEX foo
|
293
348
|
def drop_index(columns, options={})
|
294
349
|
@operations << {:op => :drop_index, :columns => Array(columns)}.merge(options)
|
295
350
|
end
|
296
351
|
|
297
352
|
# Modify a column's name in the DDL for the table.
|
353
|
+
#
|
354
|
+
# rename_column(:name, :artist_name) # RENAME COLUMN name TO artist_name
|
298
355
|
def rename_column(name, new_name, opts = {})
|
299
356
|
@operations << {:op => :rename_column, :name => name, :new_name => new_name}.merge(opts)
|
300
357
|
end
|
301
358
|
|
302
359
|
# Modify a column's default value in the DDL for the table.
|
360
|
+
#
|
361
|
+
# set_column_default(:artist_name, 'a') # ALTER COLUMN artist_name SET DEFAULT 'a'
|
303
362
|
def set_column_default(name, default)
|
304
363
|
@operations << {:op => :set_column_default, :name => name, :default => default}
|
305
364
|
end
|
306
365
|
|
307
366
|
# Modify a column's type in the DDL for the table.
|
367
|
+
#
|
368
|
+
# set_column_type(:artist_name, 'char(10)') # ALTER COLUMN artist_name TYPE char(10)
|
308
369
|
def set_column_type(name, type, opts={})
|
309
370
|
@operations << {:op => :set_column_type, :name => name, :type => type}.merge(opts)
|
310
371
|
end
|
311
372
|
|
312
373
|
# Modify a column's NOT NULL constraint.
|
374
|
+
#
|
375
|
+
# set_column_allow_null(:artist_name, false) # ALTER COLUMN artist_name SET NOT NULL
|
313
376
|
def set_column_allow_null(name, allow_null)
|
314
377
|
@operations << {:op => :set_column_null, :name => name, :null => allow_null}
|
315
378
|
end
|