sequel 2.6.0 → 2.7.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.
- data/CHANGELOG +64 -0
- data/Rakefile +1 -1
- data/lib/sequel_core/adapters/jdbc.rb +6 -2
- data/lib/sequel_core/adapters/jdbc/oracle.rb +23 -0
- data/lib/sequel_core/adapters/oracle.rb +4 -77
- data/lib/sequel_core/adapters/postgres.rb +39 -26
- data/lib/sequel_core/adapters/shared/mssql.rb +0 -1
- data/lib/sequel_core/adapters/shared/mysql.rb +1 -1
- data/lib/sequel_core/adapters/shared/oracle.rb +82 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +65 -46
- data/lib/sequel_core/core_ext.rb +10 -0
- data/lib/sequel_core/core_sql.rb +7 -0
- data/lib/sequel_core/database.rb +22 -0
- data/lib/sequel_core/database/schema.rb +1 -1
- data/lib/sequel_core/dataset.rb +29 -11
- data/lib/sequel_core/dataset/sql.rb +27 -7
- data/lib/sequel_core/migration.rb +20 -2
- data/lib/sequel_core/object_graph.rb +24 -10
- data/lib/sequel_core/schema/generator.rb +22 -9
- data/lib/sequel_core/schema/sql.rb +13 -9
- data/lib/sequel_core/sql.rb +27 -2
- data/lib/sequel_model/association_reflection.rb +251 -141
- data/lib/sequel_model/associations.rb +114 -61
- data/lib/sequel_model/base.rb +25 -21
- data/lib/sequel_model/eager_loading.rb +17 -40
- data/lib/sequel_model/hooks.rb +25 -24
- data/lib/sequel_model/record.rb +29 -51
- data/lib/sequel_model/schema.rb +1 -1
- data/lib/sequel_model/validations.rb +13 -3
- data/spec/adapters/postgres_spec.rb +104 -18
- data/spec/adapters/spec_helper.rb +4 -1
- data/spec/integration/eager_loader_test.rb +5 -4
- data/spec/integration/spec_helper.rb +4 -1
- data/spec/sequel_core/connection_pool_spec.rb +24 -24
- data/spec/sequel_core/core_sql_spec.rb +12 -0
- data/spec/sequel_core/dataset_spec.rb +77 -2
- data/spec/sequel_core/expression_filters_spec.rb +6 -0
- data/spec/sequel_core/object_graph_spec.rb +40 -2
- data/spec/sequel_core/schema_spec.rb +13 -0
- data/spec/sequel_model/association_reflection_spec.rb +8 -8
- data/spec/sequel_model/associations_spec.rb +164 -3
- data/spec/sequel_model/caching_spec.rb +2 -1
- data/spec/sequel_model/eager_loading_spec.rb +107 -3
- data/spec/sequel_model/hooks_spec.rb +38 -22
- data/spec/sequel_model/model_spec.rb +11 -35
- data/spec/sequel_model/plugins_spec.rb +4 -2
- data/spec/sequel_model/record_spec.rb +8 -5
- data/spec/sequel_model/validations_spec.rb +25 -0
- data/spec/spec_config.rb +4 -3
- metadata +21 -19
@@ -10,32 +10,35 @@ module Sequel
|
|
10
10
|
|
11
11
|
SELECT_CURRVAL = "SELECT currval('%s')".freeze
|
12
12
|
SELECT_CUSTOM_SEQUENCE = <<-end_sql
|
13
|
-
SELECT CASE
|
13
|
+
SELECT '"' || name.nspname || '"."' || CASE
|
14
14
|
WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
|
15
15
|
substr(split_part(def.adsrc, '''', 2),
|
16
16
|
strpos(split_part(def.adsrc, '''', 2), '.')+1)
|
17
17
|
ELSE split_part(def.adsrc, '''', 2)
|
18
|
-
END
|
18
|
+
END || '"'
|
19
19
|
FROM pg_class t
|
20
20
|
JOIN pg_namespace name ON (t.relnamespace = name.oid)
|
21
21
|
JOIN pg_attribute attr ON (t.oid = attrelid)
|
22
22
|
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
|
23
23
|
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
|
24
|
-
WHERE
|
25
|
-
AND cons.contype = 'p'
|
24
|
+
WHERE cons.contype = 'p'
|
26
25
|
AND def.adsrc ~* 'nextval'
|
26
|
+
AND name.nspname = '%s'
|
27
|
+
AND t.relname = '%s'
|
27
28
|
end_sql
|
28
29
|
SELECT_PK = <<-end_sql
|
29
30
|
SELECT pg_attribute.attname
|
30
|
-
FROM pg_class, pg_attribute, pg_index
|
31
|
-
WHERE pg_class.oid = pg_attribute.attrelid
|
32
|
-
pg_class.
|
33
|
-
|
34
|
-
pg_index.
|
35
|
-
|
31
|
+
FROM pg_class, pg_attribute, pg_index, pg_namespace
|
32
|
+
WHERE pg_class.oid = pg_attribute.attrelid
|
33
|
+
AND pg_class.relnamespace = pg_namespace.oid
|
34
|
+
AND pg_class.oid = pg_index.indrelid
|
35
|
+
AND pg_index.indkey[0] = pg_attribute.attnum
|
36
|
+
AND pg_index.indisprimary = 't'
|
37
|
+
AND pg_namespace.nspname = '%s'
|
38
|
+
AND pg_class.relname = '%s'
|
36
39
|
end_sql
|
37
40
|
SELECT_SERIAL_SEQUENCE = <<-end_sql
|
38
|
-
SELECT seq.relname
|
41
|
+
SELECT '"' || name.nspname || '"."' || seq.relname || '"'
|
39
42
|
FROM pg_class seq, pg_attribute attr, pg_depend dep,
|
40
43
|
pg_namespace name, pg_constraint cons
|
41
44
|
WHERE seq.oid = dep.objid
|
@@ -46,7 +49,8 @@ module Sequel
|
|
46
49
|
AND attr.attrelid = cons.conrelid
|
47
50
|
AND attr.attnum = cons.conkey[1]
|
48
51
|
AND cons.contype = 'p'
|
49
|
-
AND
|
52
|
+
AND name.nspname = '%s'
|
53
|
+
AND seq.relname = '%s'
|
50
54
|
end_sql
|
51
55
|
|
52
56
|
# Depth of the current transaction on this connection, used
|
@@ -64,15 +68,15 @@ module Sequel
|
|
64
68
|
end
|
65
69
|
|
66
70
|
# Get the primary key and sequence for the given table.
|
67
|
-
def sequence(table)
|
68
|
-
sql = SELECT_SERIAL_SEQUENCE % table
|
71
|
+
def sequence(schema, table)
|
72
|
+
sql = SELECT_SERIAL_SEQUENCE % [schema, table]
|
69
73
|
@db.log_info(sql)
|
70
74
|
execute(sql) do |r|
|
71
75
|
seq = single_value(r)
|
72
76
|
return seq if seq
|
73
77
|
end
|
74
78
|
|
75
|
-
sql = SELECT_CUSTOM_SEQUENCE % table
|
79
|
+
sql = SELECT_CUSTOM_SEQUENCE % [schema, table]
|
76
80
|
@db.log_info(sql)
|
77
81
|
execute(sql) do |r|
|
78
82
|
return single_value(r)
|
@@ -80,8 +84,8 @@ module Sequel
|
|
80
84
|
end
|
81
85
|
|
82
86
|
# Get the primary key for the given table.
|
83
|
-
def primary_key(table)
|
84
|
-
sql = SELECT_PK % table
|
87
|
+
def primary_key(schema, table)
|
88
|
+
sql = SELECT_PK % [schema, table]
|
85
89
|
@db.log_info(sql)
|
86
90
|
execute(sql) do |r|
|
87
91
|
return single_value(r)
|
@@ -93,8 +97,6 @@ module Sequel
|
|
93
97
|
module DatabaseMethods
|
94
98
|
PREPARED_ARG_PLACEHOLDER = '$'.lit.freeze
|
95
99
|
RE_CURRVAL_ERROR = /currval of sequence "(.*)" is not yet defined in this session|relation "(.*)" does not exist/.freeze
|
96
|
-
RELATION_QUERY = {:from => [:pg_class], :select => [:relname]}.freeze
|
97
|
-
RELATION_FILTER = "(relkind = 'r') AND (relname !~ '^pg|sql')".freeze
|
98
100
|
SQL_BEGIN = 'BEGIN'.freeze
|
99
101
|
SQL_SAVEPOINT = 'SAVEPOINT autopoint_%d'.freeze
|
100
102
|
SQL_COMMIT = 'COMMIT'.freeze
|
@@ -103,19 +105,29 @@ module Sequel
|
|
103
105
|
SQL_RELEASE_SAVEPOINT = 'RELEASE SAVEPOINT autopoint_%d'.freeze
|
104
106
|
SYSTEM_TABLE_REGEXP = /^pg|sql/.freeze
|
105
107
|
|
108
|
+
# The default schema to use if none is specified (default: public)
|
109
|
+
def default_schema
|
110
|
+
@default_schema ||= :public
|
111
|
+
end
|
112
|
+
|
113
|
+
# Set a new default schema to use.
|
114
|
+
def default_schema=(schema)
|
115
|
+
@default_schema = schema
|
116
|
+
end
|
117
|
+
|
106
118
|
# Remove the cached entries for primary keys and sequences when dropping a table.
|
107
119
|
def drop_table(*names)
|
108
120
|
names.each do |name|
|
109
|
-
|
110
|
-
@primary_keys.delete(
|
111
|
-
@primary_key_sequences.delete(
|
121
|
+
name = quote_schema_table(name)
|
122
|
+
@primary_keys.delete(name)
|
123
|
+
@primary_key_sequences.delete(name)
|
112
124
|
end
|
113
125
|
super
|
114
126
|
end
|
115
127
|
|
116
128
|
# Always CASCADE the table drop
|
117
129
|
def drop_table_sql(name)
|
118
|
-
"DROP TABLE #{name} CASCADE"
|
130
|
+
"DROP TABLE #{quote_schema_table(name)} CASCADE"
|
119
131
|
end
|
120
132
|
|
121
133
|
# PostgreSQL specific index SQL.
|
@@ -128,9 +140,8 @@ module Sequel
|
|
128
140
|
filter = " WHERE #{filter_expr(filter)}" if filter
|
129
141
|
case index_type
|
130
142
|
when :full_text
|
131
|
-
|
132
|
-
|
133
|
-
expr = "(to_tsvector(#{lang}#{cols}))"
|
143
|
+
cols = Array(index[:columns]).map{|x| :COALESCE[x, '']}.sql_string_join(' ')
|
144
|
+
expr = "(to_tsvector(#{literal(index[:language] || 'simple')}, #{literal(cols)}))"
|
134
145
|
index_type = :gin
|
135
146
|
when :spatial
|
136
147
|
index_type = :gist
|
@@ -152,17 +163,8 @@ module Sequel
|
|
152
163
|
|
153
164
|
# Support :schema__table format for table
|
154
165
|
def schema(table_name=nil, opts={})
|
155
|
-
|
156
|
-
|
157
|
-
t, c, a = dataset.send(:split_symbol, table_name)
|
158
|
-
opts[:schema] ||= t
|
159
|
-
table_name = c
|
160
|
-
when SQL::QualifiedIdentifier
|
161
|
-
opts[:schema] ||= table_name.table
|
162
|
-
table_name = table_name.column
|
163
|
-
when SQL::Identifier
|
164
|
-
table_name = table_name.value
|
165
|
-
end
|
166
|
+
schema, table_name = schema_and_table(table_name) if table_name
|
167
|
+
opts[:schema] = schema if schema
|
166
168
|
super(table_name, opts)
|
167
169
|
end
|
168
170
|
|
@@ -185,9 +187,27 @@ module Sequel
|
|
185
187
|
@server_version
|
186
188
|
end
|
187
189
|
|
190
|
+
# Whether the given table exists in the database
|
191
|
+
#
|
192
|
+
# Options:
|
193
|
+
# * :schema - The schema to search (default_schema by default)
|
194
|
+
# * :server - The server to use
|
195
|
+
def table_exists?(table, opts={})
|
196
|
+
schema, table = schema_and_table(table)
|
197
|
+
opts[:schema] ||= schema
|
198
|
+
tables(opts){|ds| !ds.first(:relname=>table.to_s).nil?}
|
199
|
+
end
|
200
|
+
|
188
201
|
# Array of symbols specifying table names in the current database.
|
189
|
-
|
190
|
-
|
202
|
+
# The dataset used is yielded to the block if one is provided,
|
203
|
+
# otherwise, an array of symbols of table names is returned.
|
204
|
+
#
|
205
|
+
# Options:
|
206
|
+
# * :schema - The schema to search (default_schema by default)
|
207
|
+
# * :server - The server to use
|
208
|
+
def tables(opts={})
|
209
|
+
ds = self[:pg_class].join(:pg_namespace, :oid=>:relnamespace, 'r'=>:relkind, :nspname=>(opts[:schema]||default_schema).to_s).select(:relname).exclude(:relname.like(SYSTEM_TABLE_REGEXP)).server(opts[:server])
|
210
|
+
block_given? ? yield(ds) : ds.map{|r| r[:relname].to_sym}
|
191
211
|
end
|
192
212
|
|
193
213
|
# PostgreSQL supports multi-level transactions using save points.
|
@@ -273,14 +293,14 @@ module Sequel
|
|
273
293
|
# cached, and if the primary key for a table is changed, the
|
274
294
|
# @primary_keys instance variable should be reset manually.
|
275
295
|
def primary_key_for_table(conn, table)
|
276
|
-
@primary_keys
|
296
|
+
@primary_keys[quote_schema_table(table)] ||= conn.primary_key(*schema_and_table(table))
|
277
297
|
end
|
278
298
|
|
279
299
|
# Returns primary key for the given table. This information is
|
280
300
|
# cached, and if the primary key for a table is changed, the
|
281
301
|
# @primary_keys instance variable should be reset manually.
|
282
302
|
def primary_key_sequence_for_table(conn, table)
|
283
|
-
@primary_key_sequences
|
303
|
+
@primary_key_sequences[quote_schema_table(table)] ||= conn.sequence(*schema_and_table(table))
|
284
304
|
end
|
285
305
|
|
286
306
|
# Set the default of the row to NULL if it is blank, and set
|
@@ -330,7 +350,7 @@ module Sequel
|
|
330
350
|
else
|
331
351
|
ds.select_more!(:pg_class__relname___table)
|
332
352
|
end
|
333
|
-
ds.join!(:pg_namespace, :oid=>:pg_class__relnamespace, :nspname=>opts[:schema] ||
|
353
|
+
ds.join!(:pg_namespace, :oid=>:pg_class__relnamespace, :nspname=>(opts[:schema] || default_schema).to_s) if opts[:schema] || !opts.include?(:schema)
|
334
354
|
ds
|
335
355
|
end
|
336
356
|
end
|
@@ -401,10 +421,9 @@ module Sequel
|
|
401
421
|
# PostgreSQL specific full text search syntax, using tsearch2 (included
|
402
422
|
# in 8.3 by default, and available for earlier versions as an add-on).
|
403
423
|
def full_text_search(cols, terms, opts = {})
|
404
|
-
lang = opts[:language]
|
405
|
-
cols =
|
406
|
-
|
407
|
-
filter("to_tsvector(#{lang}#{cols}) @@ to_tsquery(#{lang}#{terms})")
|
424
|
+
lang = opts[:language] || 'simple'
|
425
|
+
cols = Array(cols).map{|x| :COALESCE[x, '']}.sql_string_join(' ')
|
426
|
+
filter("to_tsvector(#{literal(lang)}, #{literal(cols)}) @@ to_tsquery(#{literal(lang)}, #{literal(Array(terms).join(' | '))})")
|
408
427
|
end
|
409
428
|
|
410
429
|
# Insert given values into the database.
|
data/lib/sequel_core/core_ext.rb
CHANGED
@@ -52,6 +52,16 @@ class Module
|
|
52
52
|
|
53
53
|
private
|
54
54
|
|
55
|
+
# Define instance method(s) that calls class method(s) of the
|
56
|
+
# same name, caching the result in an instance variable. Define
|
57
|
+
# standard attr_writer method for modifying that instance variable
|
58
|
+
def class_attr_overridable(*meths)
|
59
|
+
meths.each{|meth| class_eval("def #{meth}; @#{meth}.nil? ? (@#{meth} = self.class.#{meth}) : @#{meth} end")}
|
60
|
+
attr_writer(*meths)
|
61
|
+
public(*meths)
|
62
|
+
public(*meths.collect{|m|"#{m}="})
|
63
|
+
end
|
64
|
+
|
55
65
|
# Define instance method(s) that calls class method(s) of the
|
56
66
|
# same name. Replaces the construct:
|
57
67
|
#
|
data/lib/sequel_core/core_sql.rb
CHANGED
@@ -11,6 +11,13 @@ class Array
|
|
11
11
|
::Sequel::SQL::CaseExpression.new(self, default, expression)
|
12
12
|
end
|
13
13
|
|
14
|
+
# Return a Sequel::SQL::Array created from this array. Used if this array contains
|
15
|
+
# all two pairs and you want it treated as an SQL array instead of a ordered hash-like
|
16
|
+
# conditions.
|
17
|
+
def sql_array
|
18
|
+
::Sequel::SQL::SQLArray.new(self)
|
19
|
+
end
|
20
|
+
|
14
21
|
# Return a Sequel::SQL::BooleanExpression created from this array, matching all of the
|
15
22
|
# conditions.
|
16
23
|
def sql_expr
|
data/lib/sequel_core/database.rb
CHANGED
@@ -495,6 +495,11 @@ module Sequel
|
|
495
495
|
def connection_pool_default_options
|
496
496
|
{}
|
497
497
|
end
|
498
|
+
|
499
|
+
# Sequel doesn't use database schema's by default.
|
500
|
+
def default_schema
|
501
|
+
nil
|
502
|
+
end
|
498
503
|
|
499
504
|
# SQL to ROLLBACK a transaction.
|
500
505
|
def rollback_transaction_sql
|
@@ -512,6 +517,23 @@ module Sequel
|
|
512
517
|
raise exception
|
513
518
|
end
|
514
519
|
end
|
520
|
+
|
521
|
+
# Split the schema information from the table
|
522
|
+
def schema_and_table(table_name)
|
523
|
+
case table_name
|
524
|
+
when Symbol
|
525
|
+
s, t, a = dataset.send(:split_symbol, table_name)
|
526
|
+
[s||default_schema, t]
|
527
|
+
when SQL::QualifiedIdentifier
|
528
|
+
[table_name.table, table_name.column]
|
529
|
+
when SQL::Identifier
|
530
|
+
[default_schema, table_name.value]
|
531
|
+
when String
|
532
|
+
[default_schema, table_name]
|
533
|
+
else
|
534
|
+
raise Error, 'table_name should be a Symbol, SQL::QualifiedIdentifier, SQL::Identifier, or String'
|
535
|
+
end
|
536
|
+
end
|
515
537
|
|
516
538
|
# Return the options for the given server by merging the generic
|
517
539
|
# options for all server with the specific options for the given
|
@@ -109,7 +109,7 @@ module Sequel
|
|
109
109
|
# DB.drop_table(:posts, :comments)
|
110
110
|
def drop_table(*names)
|
111
111
|
names.each do |n|
|
112
|
-
@schemas.delete(n.to_sym) if @schemas
|
112
|
+
@schemas.delete(n.is_a?(String) ? n.to_sym : n) if @schemas
|
113
113
|
execute_ddl(drop_table_sql(n))
|
114
114
|
end
|
115
115
|
end
|
data/lib/sequel_core/dataset.rb
CHANGED
@@ -48,7 +48,8 @@ module Sequel
|
|
48
48
|
|
49
49
|
# All methods that should have a ! method added that modifies
|
50
50
|
# the receiver.
|
51
|
-
MUTATION_METHODS = %w'and distinct exclude exists
|
51
|
+
MUTATION_METHODS = %w'add_graph_aliases and distinct exclude exists
|
52
|
+
filter from from_self full_outer_join graph
|
52
53
|
group group_and_count group_by having inner_join intersect invert join
|
53
54
|
left_outer_join limit naked or order order_by order_more paginate query reject
|
54
55
|
reverse reverse_order right_outer_join select select_all select_more
|
@@ -190,18 +191,18 @@ module Sequel
|
|
190
191
|
execute_dui(delete_sql(*args))
|
191
192
|
end
|
192
193
|
|
193
|
-
# Iterates over the records in the dataset.
|
194
|
+
# Iterates over the records in the dataset and returns set. If opts
|
195
|
+
# have been passed that modify the columns, reset the column information.
|
194
196
|
def each(opts = nil, &block)
|
195
|
-
if
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
r = transform_load(r) if transform
|
202
|
-
r = row_proc[r] if row_proc
|
203
|
-
yield r
|
197
|
+
if opts && opts.keys.any?{|o| COLUMN_CHANGE_OPTS.include?(o)}
|
198
|
+
prev_columns = @columns
|
199
|
+
begin
|
200
|
+
_each(opts, &block)
|
201
|
+
ensure
|
202
|
+
@columns = prev_columns
|
204
203
|
end
|
204
|
+
else
|
205
|
+
_each(opts, &block)
|
205
206
|
end
|
206
207
|
self
|
207
208
|
end
|
@@ -432,6 +433,23 @@ module Sequel
|
|
432
433
|
|
433
434
|
private
|
434
435
|
|
436
|
+
# Runs #graph_each if graphing. Otherwise, iterates through the records
|
437
|
+
# yielded by #fetch_rows, applying any row_proc or transform if necessary,
|
438
|
+
# and yielding the result.
|
439
|
+
def _each(opts, &block)
|
440
|
+
if @opts[:graph] and !(opts && opts[:graph] == false)
|
441
|
+
graph_each(opts, &block)
|
442
|
+
else
|
443
|
+
row_proc = @row_proc unless opts && opts[:naked]
|
444
|
+
transform = @transform
|
445
|
+
fetch_rows(select_sql(opts)) do |r|
|
446
|
+
r = transform_load(r) if transform
|
447
|
+
r = row_proc[r] if row_proc
|
448
|
+
yield r
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
435
453
|
# Execute the given SQL on the database using execute.
|
436
454
|
def execute(sql, opts={}, &block)
|
437
455
|
@db.execute(sql, {:server=>@opts[:server] || :read_only}.merge(opts), &block)
|
@@ -29,6 +29,11 @@ module Sequel
|
|
29
29
|
as_sql(literal(ae.expression), ae.aliaz)
|
30
30
|
end
|
31
31
|
|
32
|
+
# SQL fragment for the SQL array.
|
33
|
+
def array_sql(a)
|
34
|
+
a.empty? ? '(NULL)' : "(#{expression_list(a)})"
|
35
|
+
end
|
36
|
+
|
32
37
|
# SQL fragment for specifying given CaseExpression.
|
33
38
|
def case_expression_sql(ce)
|
34
39
|
sql = '(CASE '
|
@@ -363,7 +368,8 @@ module Sequel
|
|
363
368
|
# * String, Symbol: table
|
364
369
|
# * expr - specifies conditions, depends on type:
|
365
370
|
# * Hash, Array with all two pairs - Assumes key (1st arg) is column of joined table (unless already
|
366
|
-
# qualified), and value (2nd arg) is column of the last joined or primary table
|
371
|
+
# qualified), and value (2nd arg) is column of the last joined or primary table (or the
|
372
|
+
# :implicit_qualifier option).
|
367
373
|
# To specify multiple conditions on a single joined table column, you must use an array.
|
368
374
|
# Uses a JOIN with an ON clause.
|
369
375
|
# * Array - If all members of the array are symbols, considers them as columns and
|
@@ -374,13 +380,23 @@ module Sequel
|
|
374
380
|
# * Everything else - pretty much the same as a using the argument in a call to filter,
|
375
381
|
# so strings are considered literal, symbols specify boolean columns, and blockless
|
376
382
|
# filter expressions can be used. Uses a JOIN with an ON clause.
|
377
|
-
# *
|
378
|
-
#
|
383
|
+
# * options - a hash of options, with any of the following keys:
|
384
|
+
# * :table_alias - the name of the table's alias when joining, necessary for joining
|
385
|
+
# to the same table more than once. No alias is used by default.
|
386
|
+
# * :implicit_qualifer - The name to use for qualifying implicit conditions. By default,
|
387
|
+
# the last joined or primary table is used.
|
379
388
|
# * block - The block argument should only be given if a JOIN with an ON clause is used,
|
380
389
|
# in which case it yields the table alias/name for the table currently being joined,
|
381
390
|
# the table alias/name for the last joined (or first table), and an array of previous
|
382
391
|
# SQL::JoinClause.
|
383
|
-
def join_table(type, table, expr=nil,
|
392
|
+
def join_table(type, table, expr=nil, options={}, &block)
|
393
|
+
if options.is_one_of?(Symbol, String)
|
394
|
+
table_alias = options
|
395
|
+
last_alias = nil
|
396
|
+
else
|
397
|
+
table_alias = options[:table_alias]
|
398
|
+
last_alias = options[:implicit_qualifier]
|
399
|
+
end
|
384
400
|
if Dataset === table
|
385
401
|
if table_alias.nil?
|
386
402
|
table_alias_num = (@opts[:num_dataset_sources] || 0) + 1
|
@@ -398,7 +414,7 @@ module Sequel
|
|
398
414
|
raise(Sequel::Error, "can't use a block if providing an array of symbols as expr") if block_given?
|
399
415
|
SQL::JoinUsingClause.new(expr, type, table, table_alias)
|
400
416
|
else
|
401
|
-
last_alias
|
417
|
+
last_alias ||= @opts[:last_joined_table] || (first_source.is_a?(Dataset) ? 't1' : first_source)
|
402
418
|
if Hash === expr or (Array === expr and expr.all_two_pairs?)
|
403
419
|
expr = expr.collect do |k, v|
|
404
420
|
k = qualified_column_name(k, table_name) if k.is_a?(Symbol)
|
@@ -470,7 +486,7 @@ module Sequel
|
|
470
486
|
when ::Sequel::SQL::Expression
|
471
487
|
v.to_s(self)
|
472
488
|
when Array
|
473
|
-
v.all_two_pairs? ? literal(v.sql_expr) : (v
|
489
|
+
v.all_two_pairs? ? literal(v.sql_expr) : array_sql(v)
|
474
490
|
when Hash
|
475
491
|
literal(v.sql_expr)
|
476
492
|
when Time, DateTime
|
@@ -653,7 +669,11 @@ module Sequel
|
|
653
669
|
|
654
670
|
sql
|
655
671
|
end
|
656
|
-
|
672
|
+
|
673
|
+
# Same as select_sql, not aliased directly to make subclassing simpler.
|
674
|
+
def sql(*args)
|
675
|
+
select_sql(*args)
|
676
|
+
end
|
657
677
|
|
658
678
|
# SQL fragment for specifying subscripts (SQL arrays)
|
659
679
|
def subscript_sql(s)
|
@@ -13,7 +13,22 @@ module Sequel
|
|
13
13
|
# end
|
14
14
|
#
|
15
15
|
# def down
|
16
|
-
#
|
16
|
+
# # You can use raw SQL if you need to
|
17
|
+
# self << 'DROP TABLE sessions'
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# class AlterItems < Sequel::Migration
|
22
|
+
# def up
|
23
|
+
# alter_table :items do
|
24
|
+
# add_column :category, :text, :default => 'ruby'
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# def down
|
29
|
+
# alter_table :items do
|
30
|
+
# drop_column :category
|
31
|
+
# end
|
17
32
|
# end
|
18
33
|
# end
|
19
34
|
#
|
@@ -25,7 +40,10 @@ module Sequel
|
|
25
40
|
#
|
26
41
|
# See Sequel::Schema::Generator for the syntax to use for creating tables,
|
27
42
|
# and Sequel::Schema::AlterTableGenerator for the syntax to use when
|
28
|
-
# altering existing tables.
|
43
|
+
# altering existing tables. Migrations act as a proxy for the database
|
44
|
+
# given in #apply, so inside #down and #up, you can act as though self
|
45
|
+
# refers to the database. So you can use any of the Sequel::Database
|
46
|
+
# instance methods directly.
|
29
47
|
class Migration
|
30
48
|
# Creates a new instance of the migration and sets the @db attribute.
|
31
49
|
def initialize(db)
|